T3
题目:上网
此题妙处:向每个限制建一个虚点
方法:建一个虚点,虚点向k个点连边,构造线段树向虚点连边,线段树本身从下往上连
注意:由于线段树要本身连很多边,故数组开大10倍
#include <bits/stdc++.h>
using namespace std;
const int N=1000050;
const int M=6000050;
typedef long long ll;
inline int read(){
int cnt=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-') f=-f;c=getchar();}
while(isdigit(c)){cnt=(cnt<<3)+(cnt<<1)+(c^48);c=getchar();}
return cnt*f;
}
int n,s,m,a[N],node,val[N];
int fir[N],nxt[M],w[M],to[M],tot;
int du[N],nd[N];
void add(int x,int y,int z){
du[y]++;nxt[++tot]=fir[x];fir[x]=tot;to[tot]=y;w[tot]=z;
}
void modify(int x,int l,int r,int L,int R,int pos){
if(L<=l&&r<=R){add(nd[x],pos,1);return;}//线段树向虚点连边
int mid=(l+r)>>1;
if(L<=mid) modify(x<<1,l,mid,L,R,pos);
if(R>mid) modify(x<<1|1,mid+1,r,L,R,pos);
}
void build(int x,int l,int r){
if(l==r){nd[x]=l;return;}
nd[x]=++node;//nd节点编号
int mid=(l+r)>>1;build(x<<1,l,mid);build(x<<1|1,mid+1,r);
add(nd[x<<1],nd[x],0);add(nd[x<<1|1],nd[x],0);//线段树从下到上连边
}
bool topsort(){
queue<int> q;
for(int i=1;i<=node;i++){if(!du[i]) q.push(i);}
int cnt=0;
while(!q.empty()){
int x=q.front();q.pop();++cnt;
if(val[x]>1e9) return false;
if(a[x]&&val[x]>a[x]) return false;
val[x]=max(1,max(val[x],a[x]));
for(int i=fir[x];i;i=nxt[i]){
int t=to[i];val[t]=max(val[t],val[x]+w[i]);
if(--du[t]==0) q.push(t);
}
}
return cnt>=node;//判环
}
int main(){
n=node=read();
s=read();m=read();
for(int i=1;i<=s;i++){
int p=read();a[p]=read();
}
build(1,1,n);
while(m--){
int l=read(),r=read(),k=read();
int pre=l-1;
int fake=++node;//虚点
for(int i=1;i<=k;i++){
int pos=read();
add(fake,pos,0);
if(pre+1<=pos-1) modify(1,1,n,pre+1,pos-1,fake);
pre=pos;
}
if(pre+1<=r) modify(1,1,n,pre+1,r,fake);
}
if(!topsort()){
puts("Impossible");
}
else{
puts("Possible");
for(int i=1;i<=n;i++){
printf("%d ",val[i]);
}
}
return 0;
}