题解 P3588【[POI2015] PUS】

Link

题意

给一个长度为 n 的序列 as 项,给出 m 条限制,一条限制以 l,r,k,x1,x2,,xk 描述,表示在 [l,r] 区间中,ax1,ax2,,axk 都严格大于没被选中的数。

求一种构造方案。

1sn105,1m2×105,k3×105

思路

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

首先看到大于,可以想到差分约束,但是要是直接暴力连边的话边数是 O(k(rl+1k))=O(n2m) 的。显然不能通过。

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

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

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

时间复杂度 O((k+m)logn)

注意,经我测试,极限数据下边数不少于 5.5×106,点数不少于 6×105,许多题解也因此被我 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 @   ffffyc  阅读(1)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示