[BZOJ]4383: [POI2015]Pustynia
题解: 线段树优化建图 分割查询区间 建源点优化边集 然后跑拓扑排序即可 细节较多
#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 JudgeSubmit: 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
2 7
5 3
1 4 2 2 3
4 5 1 4
Sample Output
TAK
6 7 1000000000 6 3
6 7 1000000000 6 3