[NOI2021] 轻重边
去年NOI的D1T1。其实感觉也没有那么难。
主要是如何快速修改路径上点的非路径连边。一个一个修改是不可能的,只能把边的修改转化成点的修改。于是想到每次修改都给路径上的点赋一个从未出现的颜色值,这样一来路径边和其它边就区分出来了:路径边的两端颜色相同,而其它边则两端颜色不同(这就体现出找从未出现过的颜色的重要性啦)。一开始由于默认的都是轻边,给每个点赋值不一样的颜色即可,到时候选颜色从 \(m+1\) 开始。
于是考虑线段树维护区间相同且相邻的元素对的个数,顺便记录区间的左右元素的颜色,合并的时候特判变化量即可。既然放在树上就要另外注意一些问题,比如两个点要分别维护ans,因为一个ans只能代表一条链(是指从lca到自身的这条链),然后在swap两个节点时两个ans也需要交换。最后两个点在一条重链上时要判断的是两个答案的左颜色是否相同。
许久未写树剖了,手生了,许多东西都淡忘了。好悲惨。记住while里判断的是两个点top的深度关系,记住线段树要开4倍。虽然这很简单,但我确实忘了。
除去这些应该还是比较好写的。
code
#include<bits/stdc++.h>
//#define zczc
const int N=100010;
using namespace std;
inline void read(int &wh){
wh=0;int f=1;char w=getchar();
while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
wh*=f;return;
}
inline void swap(int &s1,int &s2){
int s3=s1;s1=s2;s2=s3;return;
}
struct aa{
int data,lc,rc;
}newone_aa,ss;
inline void swap_aa(aa &s1,aa &s2){
aa s3=s1;s1=s2;s2=s3;return;
}
inline aa operator +(aa s1,aa s2){
aa an;an.lc=s1.lc,an.rc=s2.rc;
an.data=s1.data+s2.data+(s1.rc==s2.lc&&s1.rc!=0);
return an;
}
inline void print(aa wh){
printf("%d %d %d\n",wh.data,wh.lc,wh.rc);
}
#define lc (wh<<1)
#define rc (wh<<1|1)
#define mid (t[wh].l+t[wh].r>>1)
struct node{
int l,r;
bool lazy;int ly;
aa data;
}t[N<<2],newone;
inline void pushup(int wh){
t[wh].data=t[lc].data+t[rc].data;
}
inline void pushnow(int wh,int val){
t[wh].lazy=true;t[wh].ly=val;
t[wh].data=(aa){t[wh].r-t[wh].l,val,val};
}
inline void pushdown(int wh){
if(t[wh].lazy){
pushnow(lc,t[wh].ly);
pushnow(rc,t[wh].ly);
t[wh].lazy=false;
}
}
inline void build(int wh,int l,int r){
t[wh].data=(aa){0,l,r};
t[wh].l=l,t[wh].r=r;
t[wh].lazy=false;
if(l==r)return;
build(lc,l,mid);
build(rc,mid+1,r);
//pushup(wh);
}
inline aa work(int wh,int wl,int wr){
if(wl<=t[wh].l&&t[wh].r<=wr)return t[wh].data;
pushdown(wh);
if(wl<=mid&&wr>mid)return work(lc,wl,wr)+work(rc,wl,wr);
else if(wl<=mid)return work(lc,wl,wr);
else if(wr>mid)return work(rc,wl,wr);
//printf("work:%d %d %d\n",wh,wl,wr);
//print(an);
}
inline void change(int wh,int wl,int wr,int val){
if(wl<=t[wh].l&&t[wh].r<=wr){
pushnow(wh,val);return;
}
pushdown(wh);
if(wl<=mid)change(lc,wl,wr,val);
if(wr>mid)change(rc,wl,wr,val);
pushup(wh);return;
}
#undef lc
#undef rc
#undef mid
struct edge{
int t,next;
}e[N<<1];
int head[N],esum;
inline void add(int fr,int to){
e[++esum]=(edge){to,head[fr]};head[fr]=esum;
}
int m,n;
int size[N],son[N],lg[N],d[N],nxt[N][25];
void dfs(int wh,int fa,int deep){
size[wh]=1;d[wh]=deep;nxt[wh][0]=fa;
for(int i=1;i<=lg[d[wh]];i++)nxt[wh][i]=nxt[nxt[wh][i-1]][i-1];
for(int i=head[wh],th;i;i=e[i].next){
if((th=e[i].t)==fa)continue;
dfs(th,wh,deep+1);size[wh]+=size[th];
if(size[th]>size[son[wh]])son[wh]=th;
}
}
inline int lca(int s1,int s2){
if(d[s1]<d[s2])swap(s1,s2);
for(int i=lg[d[s1]];i>=0;i--){
if(d[nxt[s1][i]]>=d[s2]){
s1=nxt[s1][i];
}
}
if(s1==s2)return s1;
for(int i=lg[d[s1]];i>=0;i--){
if(nxt[s1][i]^nxt[s2][i]){
s1=nxt[s1][i],s2=nxt[s2][i];
}
}
return nxt[s1][0];
}
int cnt,top[N],id[N];
void dfs2(int wh,int ntop,int fa){
top[wh]=ntop;id[wh]=++cnt;
if(son[wh])dfs2(son[wh],ntop,wh);
for(int i=head[wh],th;i;i=e[i].next){
if((th=e[i].t)==fa)continue;if(th==son[wh])continue;
dfs2(th,th,wh);
}
}
void solve(){
esum=cnt=0;
memset(head,0,sizeof(head));
memset(size,0,sizeof(size));
memset(son,0,sizeof(son));
memset(nxt,0,sizeof(nxt));
memset(d,0,sizeof(d));
memset(top,0,sizeof(top));
memset(id,0,sizeof(id));
read(m);read(n);int s1,s2,color=m+1;
for(int i=1;i<m;i++){
read(s1);read(s2);
add(s1,s2);add(s2,s1);
}
dfs(1,0,1);dfs2(1,1,0);
build(1,1,m);
//for(int i=1;i<=m;i++)printf("%d\n",id[i]);
while(n--){
int op,a,b;read(op);read(a);read(b);int ll=lca(a,b);
if(op==1){
color++;
while(top[a]^top[b]){
if(d[top[a]]<d[top[b]])swap(a,b);
change(1,id[top[a]],id[a],color);
a=nxt[top[a]][0];
}
if(d[a]<d[b])swap(a,b);
change(1,id[b],id[a],color);
}
else{
aa ana={0,0,0},anb={0,0,0};
while(top[a]^top[b]){
if(d[top[a]]<d[top[b]])swap(a,b),swap_aa(ana,anb);
ana=work(1,id[top[a]],id[a])+ana;
a=nxt[top[a]][0];
}
if(d[a]<d[b])swap(a,b),swap_aa(ana,anb);
ana=work(1,id[b],id[a])+ana;
printf("%d\n",ana.data+anb.data+(ana.lc==anb.lc&&ana.lc!=0));
}
//color++;
}
}
signed main(){
#ifdef zczc
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
lg[0]=1;
for(int i=1;i<N;i++)lg[i]=lg[i>>1]+1;
int T;read(T);
while(T--){
solve();
}
return 0;
}
一如既往,万事胜意