zoukankan      html  css  js  c++  java
  • 解题: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
  • 相关阅读:
    vue实现左右两列竖直分别滑动,且双向关联的选项卡(一)
    根据对象的某个字段(值为数字)排序
    如何将data中字符传的换行正常显示
    HBase集群搭建部分配置
    YARN详解
    常用查询函数
    分桶表
    hive分区表
    xsync分发脚本
    ssh免密登录
  • 原文地址:https://www.cnblogs.com/ydnhaha/p/9839693.html
Copyright © 2011-2022 走看看