题解 P3588【[POI2015] PUS】

$\text{Link}$

题意

给一个长度为 $n$ 的序列 $a$ 的 $s$ 项,给出 $m$ 条限制,一条限制以 $l,r,k,x_1,x_2,\cdot\cdot\cdot,x_k$ 描述,表示在 $[l,r]$ 区间中,$a_{x_1},a_{x_2},\cdot\cdot\cdot,a_{x_k}$ 都严格大于没被选中的数。

求一种构造方案。

$1\le s\le n\le10^5,1\le m\le 2\times 10^5,\sum k\le 3\times 10^5$

思路

模拟赛 $\text C$ 题,赛时做出来了!!1

首先看到大于,可以想到差分约束,但是要是直接暴力连边的话边数是 $O(\sum k(r-l+1-k))=O(n^2m)$ 的。显然不能通过。

稍加思考可以想到建立两个虚点,两边分别向虚点连边(或被虚点连向),边数是 $O(\sum k+\sum r-l+1-k)=O(nm)$ 的。仍然不能通过。

考虑到第二部分为整个区间被 $k$ 个位置隔开的若干个子区间,直接由子区间向虚点连边,考虑线段树优化建图,边数为 $O(\sum k+\sum \log (r-l+1-k))=O(\sum k+m\log n)$ 的,此时边数已在合理范围内。

接下来考虑解决原问题。考虑拓扑排序,可以同时求出是否有环和最长路,最开始需要先把给出的 $s$ 项的最长路设定为给出的,其余设定为 $1$,此时便可以进行拓扑排序了。

时间复杂度 $O((\sum k+m)\log n)$。

注意,经我测试,极限数据下边数不少于 $5.5\times 10^6$,点数不少于 $6\times 10^5$,许多题解也因此被我 hack 了。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff

}
const int N=6e5+10,E=6e6+10;
int n,m,s,r[N],ind[N];
int cnt,head[N]; 
struct Edge{
    int to,nxt,w;
}a[E];
inline void add(int u,int v,int w){
    cnt++;
    a[cnt].w=w;
    a[cnt].to=v;
    a[cnt].nxt=head[u];
    head[u]=cnt;
    ind[v]++;
}
int id;
int num[N];
#define ls (rt<<1)
#define rs (rt<<1|1)
inline void build(int rt,int l,int r){
    if(l==r){
        num[rt]=l;
        return ;
    }
    num[rt]=++id;
    int mid=l+r>>1;
    build(ls,l,mid);
    build(rs,mid+1,r); 
    add(num[ls],num[rt],0);
    add(num[rs],num[rt],0);
}
inline void add(int rt,int l,int r,int L,int R,int u){
    if(L<=l&&r<=R){
        add(num[rt],u,0);
        return ;
    }
    int mid=l+r>>1;
    if(L<=mid) add(ls,l,mid,L,R,u);
    if(R> mid) add(rs,mid+1,r,L,R,u);
}
int dis[N];
bool vis[N];
inline int topo(){
    queue<int>q;
    for(int i=1;i<=id;i++){
        dis[i]=max(dis[i],1);
        if(!ind[i]) q.push(i);
    }
    while(!q.empty()){
        int cur=q.front();
        q.pop();
        vis[cur]=1;
        for(int i=head[cur];i;i=a[i].nxt){
            int t=a[i].to; 
            dis[t]=max(dis[t],dis[cur]+a[i].w);
            if(r[t]&&dis[t]>r[t]) return -1;
            if(--ind[t]==0)
                q.push(t);
        }
    }
    for(int i=1;i<=id;i++)
        if(!vis[i]||dis[i]>1e9)
            return -1;
    return 1;
}
int main(){
//  freopen("data_C2.in","r",stdin);
//  freopen("data_C2.out","w",stdout); 
    n=id=read(),s=read(),m=read();
    build(1,1,n);
    for(int i=1;i<=s;i++){
        int p=read();
        r[p]=dis[p]=read();
    } 
    while(m--){
        int l=read(),r=read(),k=read();
        id++;
        int cur=l-1;
        for(int i=1;i<=k;i++){
            int p=read();
            add(id,p,1);
            if(p-1!=cur)
                add(1,1,n,cur+1,p-1,id);
            if(i==k&&p<r)
                add(1,1,n,p+1,r,id);
            cur=p;
        }
    }
    if(~topo()){
//      printf("%d %d\n",cnt,id);
        puts("TAK");
        for(int i=1;i<=n;i++)
            printf("%d ",dis[i]);
    }else{
        puts("NIE");
    }
}

再见 qwq~

posted @ 2021-08-04 13:26  ffffyc  阅读(5)  评论(0)    收藏  举报  来源