解题:POI 2015 PUS

题面

还以为是差分约束,原来拓扑排序也能解决这样的问题=。=

类似差分约束的建图方式,我们把大小关系看做有向边。这样一来图上是不允许存在环的,于是我们可以做拓扑排序。然后问题来了,边数非常大,根本建不出图来=。=

不过我们有一个套路的做法,为每个区间配一个虚点,然后连边时先连到虚点再连到各个目标点。然后问题又来了,这样连边其实是$O(len^2)$的,$len$为区间长度,如果有个很大的区间这就萎了=。=

那什么东西解决区间问题好用呢?线段树— —我们用线段树优化建图,每次直接从虚点连到区间上,这样最多会连出来$k+klog$ $n$条边(点向虚点连的+虚点向区间连的),然后线段树内还有$4*n$条边,总共大概有不到570万条边,还可以接受。再之后做拓扑排序就可以了

注意数值的最大值和连边时的边权

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=600005,M=3400005,maxx=1e9;
 6 int num[N],ls[N],rs[N]; 
 7 int vis[N],ins[N],dp[N],mem[N],que[N];
 8 int p[N],noww[M],goal[M],val[M],deg[N];
 9 int n,s,m,l,r,k,f,b,rd,t1,t2,t3,tn,cnt,tot,pos;
10 void GG(){printf("NIE"),exit(0);}
11 void link(int f,int t,int v)
12 {
13     noww[++cnt]=p[f],p[f]=cnt;
14     goal[cnt]=t,val[cnt]=v,deg[t]++;
15 }
16 void Create(int nde,int l,int r)
17 {
18     if(l==r) num[l]=nde;
19     else 
20     {
21         int mid=(l+r)/2;
22         ls[nde]=++tot,rs[nde]=++tot;
23         link(nde,ls[nde],0),link(nde,rs[nde],0);
24         Create(ls[nde],l,mid),Create(rs[nde],mid+1,r);
25     }
26 }
27 void Change(int nde,int l,int r,int nl,int nr,int task)
28 {
29     if(l>nr||r<nl) 
30         return ;
31     else if(l>=nl&&r<=nr)
32         link(task,nde,1);
33     else
34     {
35         int mid=(l+r)/2;
36         Change(ls[nde],l,mid,nl,nr,task);
37         Change(rs[nde],mid+1,r,nl,nr,task);
38     }
39 }
40 bool DFS(int nde)
41 {
42     vis[nde]=ins[nde]=true;
43     for(int i=p[nde];i;i=noww[i])
44     {
45         if(ins[goal[i]]) return false;
46         if(!vis[goal[i]]&&!DFS(goal[i])) return false;
47     }
48     ins[nde]=false; return true;
49 } 
50 int main ()
51 {
52     scanf("%d%d%d",&n,&s,&m);
53     Create(tot=1,1,n),b=-1;
54     for(int i=1;i<=s;i++)
55     {
56         scanf("%d%d",&pos,&rd);
57         mem[num[pos]]=rd;
58     }
59     for(int i=1;i<=m;i++)
60     {
61         scanf("%d%d%d",&t1,&t2,&t3);
62         int last=t1; tot++;
63         for(int j=1;j<=t3;j++)
64         {
65             scanf("%d",&rd); link(num[rd],tot,0);
66             if(last<rd) Change(1,1,n,last,rd-1,tot);
67             last=rd+1;
68         }
69         if(last<=t2) Change(1,1,n,last,t2,tot);
70     }
71     for(int i=1;i<=tot;i++)
72         dp[i]=mem[i]?mem[i]:maxx;
73     for(int i=1;i<=tot;i++)
74     {
75         if(!vis[i]&&!DFS(i)) GG();
76         if(!deg[i]) que[++b]=i;
77     }
78     while(f<=b)
79     {
80         if(dp[tn=que[f++]]<1) GG();
81         for(int i=p[tn];i;i=noww[i])
82         {
83             if(dp[tn]-val[i]<mem[goal[i]]) GG();
84             dp[goal[i]]=min(dp[goal[i]],dp[tn]-val[i]);
85             if(!(--deg[goal[i]])) que[++b]=goal[i];
86         }
87     }
88     printf("TAK
");
89     for(int i=1;i<=n;i++) printf("%d ",dp[num[i]]);
90     return 0;
91 }
View Code
原文地址:https://www.cnblogs.com/ydnhaha/p/9839693.html