1. 程式人生 > >[BZOJ]4383: [POI2015]Pustynia

[BZOJ]4383: [POI2015]Pustynia

back 一個 細節 printf getch ... limit problem sample

題解: 線段樹優化建圖 分割查詢區間 建源點優化邊集 然後跑拓撲排序即可 細節較多

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
#include <map>
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define link(x) for(edge *j=h[x];j;j=j->next)
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,r,l) for(int i=r;i>=l;i--)
const int MAXN=1e5+10;
const double eps=1e-8;
#define ll long long
using namespace std;
struct edge{int t;edge*next;}e[MAXN*21],*h[6*MAXN],*o=e;
void add(int x,int y){o->t=y;o->next=h[x];h[x]=o++;}
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch==‘-‘)f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-‘0‘,ch=getchar();
    return x*f;
}

int pos[MAXN<<2];
int cnt,key[MAXN*6],du[MAXN*6],a[MAXN*6];

void built(int rt,int l,int r){
    if(l!=r)pos[rt]=++cnt;
    else pos[rt]=l;
    if(l==r)return ;
    int mid=(l+r)>>1;
    built(rt<<1,l,mid);
    built(rt<<1|1,mid+1,r);
    add(pos[rt<<1],pos[rt]);du[pos[rt]]++;
    add(pos[rt<<1|1],pos[rt]);du[pos[rt]]++;
}

void query(int rt,int l,int r,int ql,int qr,int k){
    if(ql>qr)return ;
    if(ql<=l&&r<=qr){add(pos[rt],k);du[k]++;return ;}
    int mid=(l+r)>>1;
    if(ql<=mid)query(rt<<1,l,mid,ql,qr,k);
    if(qr>mid)query(rt<<1|1,mid+1,r,ql,qr,k);
}

queue<int>que;
int n,s,m;
bool solve(){
    inc(i,1,cnt)if(!du[i]){
	que.push(i);
	if(!a[i])key[i]=1;
    }
    while(!que.empty()){
	int x=que.front();que.pop();
	link(x){
	    int t1;
	    if((j->t)>n)t1=key[x];
	    else t1=key[x]+1;
	    if(a[j->t]&&t1>a[j->t])return false;
	    key[j->t]=max(key[j->t],t1);
	    du[j->t]--;
	    if(!du[j->t])que.push(j->t);
	}
    }
    inc(i,1,cnt)if(du[i])return false;
    inc(i,1,cnt)if(!key[i])key[i]=1;
    inc(i,1,cnt)if(key[i]>1000000000)return false;
    return true;
}

int main(){
    n=read(),s=read(),m=read();
    int t,k;
    inc(i,1,s)t=read(),k=read(),a[t]=key[t]=k;
    cnt=n;built(1,1,n);
    int l,r;
    inc(i,1,m){
	l=read();r=read();k=read();
	int last=l;cnt++;
	inc(j,1,k){
	    t=read();
	    query(1,1,n,last,t-1,cnt);
	    add(cnt,t);du[t]++;
	    last=t+1;
	}
	query(1,1,n,last,r,cnt);
    }
    if(!solve())printf("NIE\n");
    else{
	printf("TAK\n");
	inc(i,1,n)printf("%d ",key[i]);
	printf("\n");
    }
    return 0;
}

  

4383: [POI2015]Pustynia

Time Limit: 10 Sec Memory Limit: 128 MBSec Special Judge
Submit: 685 Solved: 236
[Submit][Status][Discuss]

Description

給定一個長度為n的正整數序列a,每個數都在1到10^9範圍內,告訴你其中s個數,並給出m條信息,每條信息包含三個數l,r,k以及接下來k個正整數,表示a[l],a[l+1],...,a[r-1],a[r]裏這k個數中的任意一個都比任意一個剩下的r-l+1-k個數大(嚴格大於,即沒有等號)。

請任意構造出一組滿足條件的方案,或者判斷無解。

Input

第一行包含三個正整數n,s,m(1<=s<=n<=100000,1<=m<=200000)。
接下來s行,每行包含兩個正整數p[i],d[i](1<=p[i]<=n,1<=d[i]<=10^9),表示已知a[p[i]]=d[i],保證p[i]遞增。
接下來m行,每行一開始為三個正整數l[i],r[i],k[i](1<=l[i]<r[i]<=n,1<=k[i]<=r[i]-l[i]),接下來k[i]個正整數x[1],x[2],...,x[k[i]](l[i]<=x[1]<x[2]<...<x[k[i]]<=r[i]),表示這k[i]個數中的任意一個都比任意一個剩下的r[i]-l[i]+1-k[i]個數大。Σk <= 300,000

Output

若無解,則輸出NIE。
否則第一行輸出TAK,第二行輸出n個正整數,依次輸出序列a中每個數。

Sample Input

5 2 2
2 7
5 3
1 4 2 2 3
4 5 1 4

Sample Output

TAK
6 7 1000000000 6 3

[BZOJ]4383: [POI2015]Pustynia