csp2019备赛之刷题赛-round3
C. Winner
大意:有$n$个人打淘汰赛,每个人有$3$个权值,只要有一个权值大于对方就有可能获胜,问每个人是否有可能夺冠
$n \leq 10^5$
题解:对于三维权值,每一维都排一次序,权值大的向权值小的连边,如果有权值相同,就开两个出入的虚点,如果存在一条$x-->y$的路径就说明$x$可能打败$y$,然后缩点,没有入度的那个块里面的点都可能拿冠军
1 #include<bits/stdc++.h> 2 namespace csx_std { 3 using namespace std; 4 typedef long long ll; 5 #define FOR(i,a,b) for (register int i=(a);i<=(b);i++) 6 #define For(i,a,b) for (register int i=(a);i>=(b);i--) 7 #define mem(i,j) memset(i,j,sizeof(i)) 8 #define pii pair<int,int> 9 #define MP make_pair 10 #define fi first 11 #define se second 12 #define GO(u) for (register int j=first[u];j!=-1;j=nxt[j]) 13 const int N=4e5+5; 14 const int mod=1e9+7; 15 inline int qpow(int x,int y) {int ret=1;for (;y;y>>=1,x=1LL*x*x%mod) if (y&1) ret=1LL*ret*x%mod;return ret;} 16 inline int Inv(int x) {return qpow(x,mod-2);} 17 inline void upd(int &x,int y) {x=(1LL*x+y)%mod;return;} 18 inline int chkmax(int &x,int y) {return (x<y)?(x=y,1):0;} 19 inline int chkmin(int &x,int y) {return (x>y)?(x=y,1):0;} 20 inline int read() 21 { 22 int x=0,f=1; 23 char c=getchar(); 24 while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} 25 while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();} 26 return f*x; 27 } 28 inline void write(int x) 29 { 30 if (x<0) x=-x,putchar('-'); 31 if (x>9) write(x/10); 32 putchar(x%10+'0'); 33 return; 34 } 35 } 36 using namespace csx_std; 37 int n,q,Q[N],ans[N],vis[N],dfn[N],low[N],stck[N],dfnn=0; 38 int bl[N],du[N],cnt,top=0,siz[N],gp=0,tag=0; 39 int tot=0,first[N],nxt[N]; 40 struct E 41 { 42 int u,v; 43 }e[N]; 44 inline void add(int u,int v) 45 { 46 if (!v) return; 47 tot++; 48 nxt[tot]=first[u]; 49 first[u]=tot; 50 e[tot]=(E){u,v}; 51 // printf("(%d,%d)\n",u,v); 52 return; 53 } 54 struct data 55 { 56 int a,b,c,id; 57 }f[N]; 58 bool cmp1(const data x,const data y) {return x.a<y.a;} 59 bool cmp2(const data x,const data y) {return x.b<y.b;} 60 bool cmp3(const data x,const data y) {return x.c<y.c;} 61 inline void build() 62 { 63 int last=0; 64 sort(f+1,f+n+1,cmp1); 65 FOR(i,1,n) 66 { 67 int r=i; 68 while (f[i].a==f[r+1].a) r++; 69 if (i<r) 70 { 71 cnt++; 72 add(cnt,last); 73 FOR(j,i,r) add(f[j].id,cnt); 74 cnt++; 75 FOR(j,i,r) add(cnt,f[j].id); 76 last=cnt; 77 } 78 else add(f[i].id,last),last=f[i].id; 79 i=r; 80 } 81 82 last=0; 83 sort(f+1,f+n+1,cmp2); 84 FOR(i,1,n) 85 { 86 int r=i; 87 while (f[i].b==f[r+1].b) r++; 88 if (i<r) 89 { 90 cnt++; 91 add(cnt,last); 92 FOR(j,i,r) add(f[j].id,cnt); 93 cnt++; 94 FOR(j,i,r) add(cnt,f[j].id ); 95 last=cnt; 96 } 97 else add(f[i].id,last),last=f[i].id; 98 i=r; 99 } 100 101 last=0; 102 sort(f+1,f+n+1,cmp3); 103 FOR(i,1,n) 104 { 105 int r=i; 106 while (f[i].c==f[r+1].c) r++; 107 if (i<r) 108 { 109 cnt++; 110 add(cnt,last); 111 FOR(j,i,r) add(f[j].id,cnt); 112 cnt++; 113 FOR(j,i,r) add(cnt,f[j].id ); 114 last=cnt; 115 } 116 else add(f[i].id,last),last=f[i].id; 117 i=r; 118 } 119 return; 120 } 121 inline void Tarjan(int u) 122 { 123 dfn[u]=low[u]=++dfnn; 124 vis[u]=1; 125 stck[++top]=u; 126 GO(u) 127 { 128 int v=e[j].v; 129 if (!dfn[v]) 130 { 131 Tarjan(v); 132 chkmin(low[u],low[v]); 133 } 134 else if (vis[v]) chkmin(low[u],dfn[v]); 135 } 136 if (low[u]==dfn[u]) 137 { 138 gp++; 139 while (stck[top+1]!=u) 140 { 141 bl[stck[top]]=gp; 142 vis[stck[top]]=0; 143 if (stck[top]<=n) siz[gp]++; 144 top--; 145 } 146 } 147 return; 148 } 149 int main() 150 { 151 mem(first,-1); 152 n=read(),q=read(); 153 cnt=n; 154 FOR(i,1,n) f[i].a=read(); 155 FOR(i,1,n) f[i].b=read(); 156 FOR(i,1,n) f[i].c=read(); 157 FOR(i,1,n) f[i].id=i; 158 FOR(i,1,q) Q[i]=read(); 159 build(); 160 FOR(i,1,cnt) 161 if (!dfn[i]) Tarjan(i); 162 FOR(i,1,tot) if (bl[e[i].u]!=bl[e[i].v]) du[bl[e[i].v]]++; 163 FOR(i,1,gp) if (!du[i]) 164 { 165 tag=i; 166 break; 167 } 168 FOR(i,1,n) if (bl[i]==tag) vis[i]=1; 169 FOR(i,1,q) ans[i]=vis[Q[i]]; 170 FOR(i,1,q) 171 if (ans[i]) printf("YES\n"); 172 else printf("NO\n"); 173 return 0; 174 } 175 /* 176 4 4 177 1 2 3 4 178 1 2 4 3 179 2 1 3 4 180 1 181 2 182 3 183 4 184 */
F. Explorer
大意:给定一张无向图,每条边有权值范围$[l_i,r_i]$,要经过这条边的条件是你的容量要在$[l_i,r_i]$,现在问你有多少种容量,使得你能从$1$走到$n$
$n,m \leq 10^5 , l,r \leq 10^9$
题解:线段树分治加可撤销并查集,其中我们需要把权值区间离散化,那么我们线段树上的节点不能再使用闭区间了,否则$(mid,mid+1)$之间的权值会蒸发,改成左闭右开的区间就行了
1 #include<bits/stdc++.h> 2 namespace csx_std { 3 using namespace std; 4 typedef long long ll; 5 #define FOR(i,a,b) for (register int i=(a);i<=(b);i++) 6 #define For(i,a,b) for (register int i=(a);i>=(b);i--) 7 #define mem(i,j) memset(i,j,sizeof(i)) 8 #define pii pair<int,int> 9 #define pb push_back 10 #define MP make_pair 11 #define fi first 12 #define se second 13 #define GO(u) for (register int j=first[u];j!=-1;j=nxt[j]) 14 const int N=3e5+5; 15 const int mod=1e9+7; 16 inline int qpow(int x,int y) {int ret=1;for (;y;y>>=1,x=1LL*x*x%mod) if (y&1) ret=1LL*ret*x%mod;return ret;} 17 inline int Inv(int x) {return qpow(x,mod-2);} 18 inline void upd(int &x,int y) {x=(1LL*x+y)%mod;return;} 19 inline int chkmax(int &x,int y) {return (x<y)?(x=y,1):0;} 20 inline int chkmin(int &x,int y) {return (x>y)?(x=y,1):0;} 21 inline int read() 22 { 23 int x=0,f=1; 24 char c=getchar(); 25 while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} 26 while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();} 27 return f*x; 28 } 29 inline void write(ll x) 30 { 31 if (x<0) x=-x,putchar('-'); 32 if (x>9) write(x/10); 33 putchar(x%10+'0'); 34 return; 35 } 36 } 37 using namespace csx_std; 38 int n,m,fa[N],dep[N]; 39 ll ans=0,b[N<<1],len=0; 40 int in1[N],in2[N],in3[N],in4[N]; 41 struct data 42 { 43 int u,v,w; 44 }; 45 vector <data> vec[N<<2]; 46 inline int getfa(int x) {return (x==fa[x])?x:getfa(fa[x]);} 47 inline int con(int x,int y) 48 { 49 int fx=getfa(x),fy=getfa(y); 50 return (fx==fy); 51 } 52 inline data link(int x,int y) 53 { 54 data ret; 55 int fx=getfa(x),fy=getfa(y); 56 if (dep[fx]>dep[fy]) swap(x,y),swap(fx,fy); 57 ret.u=fx,ret.v=fy; 58 fa[fx]=fy; 59 if (dep[fx]==dep[fy]) dep[fy]++,ret.w=1; 60 else ret.w=0; 61 return ret; 62 } 63 inline void del(vector <data> V) 64 { 65 For(i,(int)V.size()-1,0) 66 { 67 dep[V[i].v]-=V[i].w; 68 fa[V[i].u]=V[i].u; 69 } 70 return; 71 } 72 inline void insert(int p,int l,int r,int L,int R,int ith) 73 { 74 if (L<=l&&r<=R) {vec[p].pb((data){in1[ith],in2[ith],0});return;} 75 if (l==r-1) return; 76 int mid=(l+r)>>1; 77 if (L<=mid) insert(p<<1,l,mid,L,R,ith); 78 if (R>mid) insert(p<<1|1,mid,r,L,R,ith); 79 return; 80 } 81 inline void solve(int p,int l,int r) 82 { 83 vector <data> rub; 84 rub.clear(); 85 FOR(i,0,(int)vec[p].size()-1) if (!con(vec[p][i].u,vec[p][i].v)) rub.pb(link(vec[p][i].u,vec[p][i].v)); 86 if (con(1,n)) {ans+=b[r]-b[l];del(rub);return;} 87 if (l==r-1) {del(rub);return;} 88 int mid=(l+r)>>1; 89 solve(p<<1,l,mid); 90 solve(p<<1|1,mid,r); 91 del(rub); 92 return; 93 } 94 inline void debug(int p,int l,int r) 95 { 96 printf("[%d,%d] : \n",l,r); 97 FOR(i,0,(int)vec[p].size()-1) 98 { 99 printf("(%d,%d) ",vec[p][i].u,vec[p][i].v); 100 } 101 putchar('\n'); 102 int mid=(l+r)>>1; 103 if (l==r) return; 104 debug(p<<1,l,mid); 105 debug(p<<1|1,mid+1,r); 106 return; 107 } 108 int main() 109 { 110 n=read(),m=read(); 111 FOR(i,1,n) fa[i]=i,dep[i]=1; 112 FOR(i,1,m) in1[i]=read(),in2[i]=read(),in3[i]=read(),in4[i]=read()+1,b[++len]=in3[i],b[++len]=in4[i]; 113 sort(b+1,b+len+1); 114 len=unique(b+1,b+len+1)-b-1; 115 FOR(i,1,m) in3[i]=lower_bound(b+1,b+len+1,in3[i])-b,in4[i]=lower_bound(b+1,b+len+1,in4[i])-b; 116 FOR(i,1,m) insert(1,1,len,in3[i],in4[i],i); 117 solve(1,1,len); 118 write(ans),putchar('\n'); 119 // debug(1,1,len); 120 return 0; 121 } 122 /* 123 5 5 124 1 2 10 40 125 2 3 10 20 126 3 5 20 40 127 2 4 10 30 128 4 5 20 40 129 */