最近在学lct,拿这道题学了动态图。
法一:
很神的分块(用vector常数太大t了。。)
按时间分块,先将覆盖整个块的边缩起来,然后枚举每一个时间对于块内的边暴力;缩点和暴力都是O(边数目)的。这样的话每个边都会被扫
O(n√)
遍,时间复杂度
O(nn√)≈6.5∗107
,然后加上我用了vector,常数巨大。。
法二:
很傻b的ufs。
用类似线段树打标记的方法dfs,记下来每次修改了数组中的哪些,每次回溯的时候暴力修改。时间复杂度
O(nlog2n)
,由于我用了vector,常数巨大。。
法三:
很神的lct。
考虑按照时间从前向后扫描,对于一个环,显然在环中第一个被删的边被删之前,这个环的奇偶性是不会改变的。所以我们选择将这条边从树中提出来,因为它所产生的影响已经确定了。
直观上来看就是在维护删除时间的最大生成树。时间复杂度
O(nlogn)
分块(TLE了):
#include<cstdio>
#include<iostream>
using namespace std;
#include<algorithm>
#include<cmath>
#include<cstring>
void in(int &x){
char c=getchar();
while(c<'0'||c>'9')c=getchar();
for(x=0;c>='0'&&c<='9';c=getchar())x=x*10+(c^'0');
}
#include<vector>
const int S=316;
//const int S=2;
struct BS{
vector< pair<int,int> > ae[320],be;
}b[320];
int fa[100005],color[100005];
int p[2];
int ptr[100005],next[200005],succ[200005],etot=1;
void addedge(int from,int to){
//printf("Addedge(%d->%d)\n",from,to);
next[etot]=ptr[from],ptr[from]=etot,succ[etot++]=to;
}
bool bdfs(int node,int nc){
if(fa[node])
if(fa[node]==p[nc])return 1;
else return 0;
else fa[node]=p[nc];
for(int i=ptr[node];i;i=next[i])
if(!bdfs(succ[i],!nc))
return 0;
return 1;
}
bool adfs(int node,int nc){
if(~color[node])
if(color[node]==nc)return 1;
else return 0;
else color[node]=nc;
for(int i=ptr[node];i;i=next[i])
if(!adfs(succ[i],!nc))
return 0;
return 1;
}
int main(){
freopen("bzoj_4025.in","r",stdin);
//freopen("bzoj_4025_block.out","w",stdout);
int n,m,T,i,j,u,v,start,end;
int tot=0;
in(n),in(m),in(T);
while(m--){
in(u),in(v),in(start),in(end);
++start;
//printf("--[%d,%d]--\n",start,end);
if(start/S<end/S){
for(i=start;i/S==start/S;++i){
b[i/S].ae[i%S].push_back(make_pair(u,v));
++tot;
}
for(i=end;i/S==end/S;--i){
b[i/S].ae[i%S].push_back(make_pair(u,v));
++tot;
}
for(i=start/S;++i<end/S;){
b[i].be.push_back(make_pair(u,v));
++tot;
}
}
else
for(i=start;i<=end;++i){
b[i/S].ae[i%S].push_back(make_pair(u,v));
++tot;
}
}
printf("%d\n",tot);
return 0;
int k,t0,t1;
bool ans;
for(i=1;i<=T;++i){
if(i==1||i%S==0){
t0=i/S;
//printf("---block(%d)---\n",t0);
//for(j=b[t0].be.size();j--;)printf("(%d,%d)\n",b[t0].be[j].first,b[t0].be[j].second);
ans=1;
memset(fa,0,sizeof(fa));
for(j=b[t0].be.size();j--;){
addedge(b[t0].be[j].first,b[t0].be[j].second),addedge(b[t0].be[j].second,b[t0].be[j].first);
if(b[t0].be[j].first==b[t0].be[j].second){
ans=0;
break;
}
}
if(ans){
for(j=b[t0].be.size();j--;)
if(!fa[b[t0].be[j].first]){
p[0]=b[t0].be[j].first,p[1]=b[t0].be[j].second;
if(!bdfs(b[t0].be[j].first,0)){
ans=0;
break;
}
}
for(j=n;j;--j)
if(!fa[j])
fa[j]=j;
}
etot=1;
memset(ptr,0,sizeof(ptr));
//printf("blockans=%d\n",ans);
}
if(ans){
t1=i%S;
//printf("---%d:(%d,%d)---\n",i,t0,t1);
//for(j=b[t0].ae[t1].size();j--;)printf("(%d,%d)\n",b[t0].ae[t1][j].first,b[t0].ae[t1][j].second);
for(j=b[t0].ae[t1].size();j--;){
addedge(fa[b[t0].ae[t1][j].first],fa[b[t0].ae[t1][j].second]),addedge(fa[b[t0].ae[t1][j].second],fa[b[t0].ae[t1][j].first]);
color[fa[b[t0].ae[t1][j].first]]=color[fa[b[t0].ae[t1][j].second]]=-1;
}
for(j=b[t0].ae[t1].size();j--;)
if(color[fa[b[t0].ae[t1][j].first]]==-1&&!adfs(fa[b[t0].ae[t1][j].first],0))
break;
if(~j)puts("No");
else puts("Yes");
etot=1;
for(j=b[t0].ae[t1].size();j--;)ptr[fa[b[t0].ae[t1][j].first]]=ptr[fa[b[t0].ae[t1][j].second]]=0;
}
else puts("No");
}
}
ufs(常数巨大):
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
const int Z=1<<17;
void in(int &x){
char c=getchar();
while(c<'0'||c>'9')c=getchar();
for(x=0;c>='0'&&c<='9';c=getchar())x=x*10+(c^'0');
}
//(node<<1)-1是它自己,node<<1是它的敌人。
vector< pair<int,int> > e[Z<<1];
int fa[200005],sz[200005];
vector< pair<int,int> > flist[Z<<1],slist[Z<<1];
void link(int node,int x,int y){//x->y
flist[node].push_back(make_pair(x,fa[x]));
fa[x]=y;
}
int find(int node,int x){
int root=fa[x],ftr=fa[x];
while(root!=fa[root])root=fa[root];
for(;ftr!=root;x=ftr,ftr=fa[ftr])link(node,x,root);
return root;
}
void merge(int node,int x,int y){
//printf("Merge(%d,%d)\n",x,y);
if(x==y)return;
if(sz[x]>sz[y])swap(x,y);
slist[node].push_back(make_pair(y,sz[y]));
sz[y]+=sz[x];
link(node,x,y);
}
int T;
int l[Z<<1],r[Z<<1];
void dfs(int node,bool ans){
//printf("---[%d,%d] %d---\n",l[node],r[node],ans);
bool now=ans;
int i;
if(ans){
for(i=e[node].size();i--;){
//printf("Addedge(%d,%d)\n",e[node][i].first,e[node][i].second);
if(find(node,e[node][i].first<<1)==find(node,e[node][i].second<<1)){
//printf("Maodun:fa[%d]=%d,fa[%d]=%d\n",e[node][i].first<<1,fa[e[node][i].first<<1],e[node][i].second<<1,fa[e[node][i].second<<1]);
now=0;
break;
}
else{
//puts("Fuhe");
//printf("%d %d\n",fa[e[node][i].first<<1],fa[e[node][i].second<<1]);
merge(node,fa[e[node][i].first<<1],find(node,(e[node][i].second<<1)-1));
merge(node,find(node,(e[node][i].first<<1)-1),fa[e[node][i].second<<1]);
}
}
}
if(node<Z)dfs(node<<1,now),dfs(node<<1|1,now);
else
if(now)puts("Yes");
else puts("No");
if(ans){
for(i=flist[node].size();i--;)fa[flist[node][i].first]=flist[node][i].second;
for(i=slist[node].size();i--;)sz[slist[node][i].first]=slist[node][i].second;
}
//cout<<fa[2]<<endl;
}
int main(){
freopen("bzoj_4025.in","r",stdin);
freopen("bzoj_4025.out","w",stdout);
int n,m,u,v,start,end;
in(n),in(m),in(T);
for(int i=T;i;--i)l[Z+i]=r[Z+i]=i;
for(int i=Z;--i;){
l[i]=l[i<<1]?l[i<<1]:l[i<<1|1];
r[i]=r[i<<1|1]?r[i<<1|1]:r[i<<1];
}
while(m--){
in(u),in(v),in(start),in(end);
for(start+=Z,end+=Z+1;end-start>1;start>>=1,end>>=1){
if(~start&1)e[start^1].push_back(make_pair(u,v));
if(end&1) e[end^1].push_back(make_pair(u,v));
}
}
for(int i=n<<1;i;--i){
fa[i]=i;
sz[i]=1;
}
int x=0;
for(start=Z,end=Z+T+1;end-start>1;++x,start>>=1,end>>=1)
if(~start&1)
dfs(start^1,1);
end=Z+T+1;
while(x--){
if(end>>x&1)
dfs(end>>x^1,1);
//cout<<"["<<l[end]<<","<<r[end]<<"]\n";
}
}
lct:
#include<cstdio>
#include<iostream>
using namespace std;
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
void in(int &x){
char c=getchar();
while(c<'0'||c>'9')c=getchar();
for(x=0;c>='0'&&c<='9';c=getchar())x=x*10+(c^'0');
}
struct LS{
int ch[2],fa;
int sz,wt,min,end;
bool swapflag;
}lct[300005];
void update(int node){
lct[node].sz=lct[lct[node].ch[0]].sz+lct[lct[node].ch[1]].sz+lct[node].wt;
lct[node].min=min(lct[node].end,min(lct[lct[node].ch[0]].min,lct[lct[node].ch[1]].min));
}
void swappaint(int node){
if(node){
swap(lct[node].ch[0],lct[node].ch[1]);
lct[node].swapflag^=1;
}
}
void pushdown(int node){
if(lct[node].swapflag){
swappaint(lct[node].ch[0]),swappaint(lct[node].ch[1]);
lct[node].swapflag^=1;
}
}
void out(int node){
printf("%d:ch[0]=%d,ch[1]=%d,fa=%d,sz=%d,wt=%d,min=%d,end=%d\n",node,lct[node].ch[0],lct[node].ch[1],lct[node].fa,lct[node].sz,lct[node].wt,lct[node].min,lct[node].end);
}
void outdfs(int node){
out(node);
pushdown(node);
if(lct[node].ch[0])outdfs(lct[node].ch[0]);
if(lct[node].ch[1])outdfs(lct[node].ch[1]);
}
bool is_top(int node){
return lct[node].fa==0||lct[lct[node].fa].ch[1]!=node&&lct[lct[node].fa].ch[0]!=node;
}
void down(int node){
if(!is_top(node))down(lct[node].fa);
pushdown(node);
}
void rot(int node){
int fa=lct[node].fa;
bool dir=lct[fa].ch[1]==node;
lct[node].fa=lct[fa].fa;
lct[fa].fa=node;
lct[lct[node].ch[!dir]].fa=fa;
lct[fa].ch[dir]=lct[node].ch[!dir];
lct[node].ch[!dir]=fa;
if(lct[lct[node].fa].ch[1]==fa)lct[lct[node].fa].ch[1]=node;
else if(lct[lct[node].fa].ch[0]==fa)lct[lct[node].fa].ch[0]=node;
update(fa);
}
void splay(int node){
down(node);
for(int fa;!is_top(node);rot(node)){
fa=lct[node].fa;
if(!is_top(fa))
if((lct[lct[fa].fa].ch[1]==fa)==(lct[fa].ch[1]==node))rot(fa);
else rot(node);
}
update(node);
}
void discon(int node){
splay(node);
lct[node].ch[1]=0;
}
void access(int node){
//printf("access(%d)\n",node);
for(discon(node);lct[node].fa;rot(node)){
discon(lct[node].fa);
lct[lct[node].fa].ch[1]=node;
}
update(node);
//outdfs(node);
//puts("");
}
void makeroot(int node){
access(node);
swappaint(node);
}
void cut(int node){
splay(node);
lct[lct[node].ch[0]].fa=lct[node].fa,lct[lct[node].ch[1]].fa=0;
lct[node].ch[0]=lct[node].ch[1]=0;
//out(node);
}
void findmin(int node){
while(lct[node].min!=lct[node].end){
pushdown(node);
if(lct[lct[node].ch[0]].min==lct[node].min)node=lct[node].ch[0];
else node=lct[node].ch[1];
}
cut(node);
}
void getchain(int u,int v){
makeroot(u);
access(v);
}
void link(int from,int to){
makeroot(from);
lct[from].fa=to;
}
struct ES{
int u,v,start,end;
}e[200005];
bool cmp(const int &a,const int &b){
return e[a].end<e[b].end;
}
vector<int> l[100005],r[100005];
int delta[100005];
int main(){
freopen("bzoj_4025.in","r",stdin);
freopen("bzoj_4025_lct.out","w",stdout);
int n,m,T,i;
in(n),in(m),in(T);
for(i=m;i;--i){
in(e[i].u),in(e[i].v),in(e[i].start),in(e[i].end);
if(++e[i].start<=e[i].end)l[e[i].start].push_back(i),r[e[i].end].push_back(i);
}
for(i=n;~i;--i)lct[i].min=lct[i].end=0x7fffffff;
for(i=m;i;--i){
lct[n+i].wt=lct[n+i].sz=1;
lct[n+i].min=lct[n+i].end=e[i].end;
}
int j,now=0;
for(i=1;i<=T;++i){
//printf("-------T:%d-------\n",i);
//link
sort(l[i].begin(),l[i].end());
for(j=l[i].size();j--;){
//printf("Add(%d)=(%d,%d,%d,%d)\n",n+l[i][j],e[l[i][j]].u,e[l[i][j]].v,e[l[i][j]].start,e[l[i][j]].end);
if(e[l[i][j]].u!=e[l[i][j]].v){
getchain(e[l[i][j]].u,e[l[i][j]].v);
if(is_top(e[l[i][j]].u)){
link(e[l[i][j]].u,n+l[i][j]);
link(n+l[i][j],e[l[i][j]].v);
access(e[l[i][j]].u);
}
else{
if(~lct[e[l[i][j]].v].sz&1){
++now;
//printf("%d %d(%d)\n",lct[e[l[i][j]].v].min,e[l[i][j]].end,l[i][j]);
--delta[min(lct[e[l[i][j]].v].min,e[l[i][j]].end)+1];
//cout<<lct[e[l[i][j]].v].min<<","<<e[l[i][j]].end<<endl;
//cout<<min(lct[e[l[i][j]].v].min,e[l[i][j]].end)+1<<endl;
//puts("Ji huan!");
}
if(lct[e[l[i][j]].v].min<e[l[i][j]].end){
findmin(e[l[i][j]].v);
link(e[l[i][j]].u,n+l[i][j]);
link(n+l[i][j],e[l[i][j]].v);
access(e[l[i][j]].u);
}
}
}
else{
++now;
--delta[e[l[i][j]].end+1];
}
}
//query
now+=delta[i];
//cout<<delta[i]<<"->"<<now<<endl;
if(now)puts("No");
else puts("Yes");
//cut
for(j=r[i].size();j--;){
//printf("Del(%d)=(%d,%d,%d,%d)\n",n+r[i][j],e[r[i][j]].u,e[r[i][j]].v,e[r[i][j]].start,e[r[i][j]].end);
cut(n+r[i][j]);
}
}
}
总结:
①做数据结构题时,务必首先考虑分块。
②考虑无序的问题时,往往需要将其有序化。比如说将环中的边按删除时间考虑。
③cut一个点时,注意如果它不在root所在的splay中,就需要将它左儿子的父指针指向它的父亲。