我在比赛(noip模拟)时看到这题,一脸懵逼,上数学课想了很久也想不完整,总有地方实现不了。后来知道了某个dalao用LCT过的,然后和kscla吹B了半个晚上,就把这题吹出来了。
先讲LCT部分,朴素的LCT可以支持在有Link和Cut操作的森林上修改路径和维护路径信息,比如最大值。
那么就可以维护只有加边情况下的动态最小生成树。
(就是假若出现环,就把环上最大的一条边Cut掉)
Lct还可以维护连通块大小。由于LCT是维护出来的森林是有序的,即一条树链上的结点在Splay上的顺序就是深度由小到大的顺序。而path-parent也是parent,对于一条没有path-parent的路径,它的第一个结点就是这个连通块的根。
既然树是有序的,也就有了相对的子树,我们就可以像静态树一样由下往上维护子树大小。
所以朴素的想法就是按顺序,每条路径将自身子树大小传给path-parent。
可以每个结点开一个other值,表示所有path-parent指向这个点的路径所在子树大小的和。
splay可以维护other的和,记为sum,splay根上的sum+(splay大小)即为这个连通块的大小。
由此也可知,对于只在splay上的操作(不涉及path-parent的更改,如,splay,Cut中的删儿子,翻转),是不会影响other的sum的正确信息的。
现在考虑更改path-parent的操作
Access:Access就是按由下到上顺序把一个点到根的路径扔进splay里,所以就按顺序统计把当前sum算进other里。
Link(x,y):先Evert(x),再splay(x),那么x就能得到x所在连通块正确的信息。
x->path-parent=y。大概想法就是用x所在连通块的信息更新y,y所在splay的path-parent,…,一路更新到根。这样其实不影响复杂度,因为相当于Access(y)。(当然也可以Access(y)后更新一次)
如果学过LCT的套路,以上就是废话了。
对于这题,sunny图的充要条件是每个连通块都有偶数个点。(每个连通块保留一棵生成树,对于每条树边,若该边相连的两个连通块大小都为偶数,则不选该边,否则就选)。
本蒟蒻考试时这点都没看出来……
LCT题的套路:答案在最小生成树上
对于边(x,y),若存在路径(x,y),无论Cut掉路径上哪一条边,边(x,y)与被Cut掉的边都是等价的,同时选或不选。即若不Cut掉的话,当某条边作为答案时,答案需与另一条边取max,故Cut掉长度最大的边最优 。
统计答案用一个维护最大值的优先队列,存树上的边。每次操作后
不断重复:若队头不在树上,或者相连的两个连通块大小都为偶数,则把队头弹出。
这样后,队头就是答案。
我LCT,洋洋洒洒300行,还请教练把时限开大了才能A。
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
using namespace std;
#define mmst(a, b) memset(a, b, sizeof(a))
#define mmcp(a, b) memcpy(a, b, sizeof(b))
#define imax(a, b) (((a)>(b)) ? (a) : (b))
typedef long long LL;
const int N=800800;
void read(int &hy)
{
hy=0;
char cc=getchar();
while(cc>'9'||cc<'0')
cc=getchar();
while(cc>='0'&&cc<='9')
{
hy=(hy<<3)+(hy<<1)+cc-'0';
cc=getchar();
}
}
int js,cnt,n,m,u[N],v[N],len[N],fa[N];
int find(int x)
{
if(fa[x]!=x)
fa[x]=find(fa[x]);
return fa[x];
}
struct yy{
int num,len;
bool operator < (const yy &a)
const{return len<a.len;}
}tu;
priority_queue<yy>q;
struct tree
{
tree *c[2],*f,*pp;
int e,me;
bool flip,other,sum,siz,a;
int d(){return f->c[1]==this;}
void sc(tree *x,int d){(c[d]=x)->f=this;}
}nil[N],*ro[N],*edge[N];
inline tree *newtree(int e,bool a)
{
nil[++cnt]=nil[0];
nil[cnt].sum=nil[cnt].siz=nil[cnt].a=a;
nil[cnt].me=nil[cnt].e=e;
return nil+cnt;
}
inline void up(tree *x)
{
x->siz=x->c[0]->siz^x->c[1]->siz^x->a;
x->me=imax(x->e,imax(x->c[0]->me,x->c[1]->me));
x->sum=x->a^x->other^x->c[0]->sum^x->c[1]->sum;
}
inline void down(tree *x)
{
if(!x->flip)
return;
x->flip=0;
swap(x->c[0],x->c[1]);
x->c[0]->flip^=1;
x->c[1]->flip^=1;
}
void work(tree *x)
{
if(x->f!=nil)
work(x->f);
down(x);
}
inline void zig(tree *x)
{
tree *y=x->f;
int d=x->d();
y->sc(x->c[!d],d);
if(y->f==nil)
x->f=nil;
else
y->f->sc(x,y->d());
x->sc(y,!d);
x->pp=y->pp;
y->pp=nil;
up(y);
}
inline void splay(tree *x)
{
work(x);
for(tree *y;x->f!=nil;)
{
y=x->f;
if(y->f!=nil)
(x->d() ^ y->d()) ? zig(x) : zig(y);
zig(x);
}
up(x);
}
inline void Access(tree *x)
{
tree *y=nil;
while(x!=nil)
{
splay(x);
if(x->c[1]!=nil)
{
x->c[1]->f=nil;
x->c[1]->pp=x;
x->other^=x->c[1]->sum;
}
x->c[1]=y;
if(y!=nil)
y->f=x;
x->other^=y->sum;
y->pp=nil;
up(x);
y=x;
x=x->pp;
}
}
inline void Evert(tree *x)
{
Access(x);
splay(x);
x->flip^=1;
}
inline void Link(tree *x,tree *y)
{
Evert(x);
splay(x);
Access(y);
splay(y);
x->pp=y;
y->other^=x->sum;
up(y);
}
inline void Cut(tree *x,tree *y)
{
Evert(x);
Access(y);
splay(x);
x->c[1]->f=nil;
x->c[1]=nil;
up(x);
}
void unite(int num,int X,int Y)
{
tree *x=ro[X];
tree *y=ro[Y];
X=find(X);
Y=find(Y);
tu.num=num;
tu.len=len[num];
if(X^Y)
{
if(js!=0)
{
Access(x);
splay(x);
Access(y);
splay(y);
if(x->sum&&y->sum)
js-=2;
}
Link(edge[num],x);
Link(edge[num],y);
fa[X]=Y;
q.push(tu);
return;
}
Evert(x);
Access(y);
splay(x);
int le=x->me;
if(le<=len[num])
return;
tree *xx=x;
while(1)
{
if(xx->e==le)
break;
if(xx->c[0]->me==le)
xx=xx->c[0];
else
xx=xx->c[1];
}
Cut(ro[u[xx-nil]],xx);
Cut(ro[v[xx-nil]],xx);
len[xx-nil]=0;
Link(x,edge[num]);
Link(y,edge[num]);
fa[X]=Y;
q.push(tu);
}
void sora()
{
bool hy=true;
while(hy&&!q.empty())
{
hy=false;
tu=q.top();
if(!len[tu.num])
{
q.pop();
hy=true;
}
else
{
tree *x=ro[u[tu.num]];
Cut(x,edge[tu.num]);
Evert(x);
if(!x->sum)
{
q.pop();
hy=true;
}
Link(x,edge[tu.num]);
}
}
}
int main()
{
nil->c[0]=nil->c[1]=nil->f=nil->pp=nil;
cin>>n>>m;
for(int i=1;i<=n;i++)
fa[i]=i;
if(n&1)
{
for(int i=1;i<=m;i++)
printf("-1\n");
return 0;
}
for(int i=1;i<=m;i++)
{
read(u[i]);
read(v[i]);
read(len[i]);
edge[i]=newtree(len[i],0);
}
for(int i=1;i<=n;i++)
ro[i]=newtree(0,1);
int biu;
js=n;
for(biu=1;biu<=m;++biu)
{
unite(biu,u[biu],v[biu]);
if(!js)
break;
printf("-1\n");
}
if(js)
return 0;
sora();
tu=q.top();
printf("%d\n",tu.len);
for(register int i=biu+1;i<=m;++i)
{
unite(i,u[i],v[i]);
sora();
tu=q.top();
printf("%d\n",tu.len);
}
return 0;
}
你知道雪为什么是白色的吗,因为她忘了自己曾经的颜色。