1,acwing 2154.梦幻布丁(启发式合并);2,祖孙询问(lca);3,acwing 2568.树链剖分
1,梦幻布丁;
启发式合并就是在合并集合的时候,小的往大的合并,不要让大的合并到小的;这样就可以将复杂度由O(n^2) 降为O(nlogn);
思路:存储对应颜色的下标序列,每次为操作1时,合并两个集合,用启发式合并;
维护颜色的段数:改变颜色时,只会影响相邻的,x,y颜色;所以对集合遍历判断即可;
判断x之前左右是不是y,是,段数-1;
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define rep1(i,a,n) for( int i=(a);i<(n);++i)
#define rep2(i,a,n) for( int i=(a);i<=(n);++i)
#define per1(i,n,a) for( int i=(n);i>(a);i--)
#define per2(i,n,a) for( int i=(n);i>=(a);i--)
#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define memset(a,i,b) memset((a),(i),sizeof (b))
#define memcpy(a,i,b) memcpy((a),(i),sizeof (b))
#define pro_q priority_queue
#define eb emplace_back
#define endl "\n"
#define lowbit(m) ((-m)&(m))
#define dbug(y) cout<<(#y)<<"\n"
#define yi first
#define er second
#define INF 0x3f3f3f3f
#define tulun int e[N],ne[N],h[N],w[N],idx;
#define add2(a,b) e[idx]=b,ne[idx]=h[a],h[a]=idx++;
#define add3(a,b,c) we[idx]=c,e[idx]=b,ne[idx]=h[a],h[a]=idx++;
#define T_solve() int T;cin>>T;while(T--)solve();
#define pi 3.14159265358979323846
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
typedef pair<pair<int,int>,pair<int,int>>PIIII;
typedef pair<long long,long long> PLL;
typedef double dob;
typedef pair<dob,dob> PDD;
const int N=1e6+10;
int color[N],n,m,cnt;
vector<int>g[N];
signed main()
{
quick_cin();
cin>>n>>m;
rep2(i,1,n)
{
cin>>color[i];
g[color[i]].eb(i);
cnt+=(color[i]!=color[i-1]);
}
while(m--)
{
int op;
cin>>op;
if(op==1)
{
int x,y;
cin>>x>>y;
if(x==y)continue;
if(g[x].size()>g[y].size())swap(g[x],g[y]);
if(!g[x].size())continue;
int v=color[g[y][0]];
for(auto u:g[x])
{
cnt-=(color[u-1]==v)+(color[u+1]==v);
}
while(g[x].size())
{
color[g[x].back()]=v;
g[y].eb(g[x].back());
g[x].pop_back();
}
}
else cout<<cnt<<endl;
}
return 0;
}
2,祖孙询问;
复习lca;
int lca(int a,int b)
{
if(d[a]<d[b])swap(a,b);
per2(k,15,0)
if(d[fa[a][k]]>=d[b])//设置哨兵的好处,如果跳出去会返回0,所以刚好满足能找到的符合小于
//d[b]且最大的a能跳到的位置;
a=fa[a][k];
if(a==b)return a;
per2(k,15,0)
if(fa[a][k]!=fa[b][k])//如果跳不到lca,就往上跳,所以最终结束条件是跳1步就达到lca;
{
a=fa[a][k];
b=fa[b][k];
}
return fa[a][0];//由上面可知,返回此时跳到位置的父节点,即为lca
}
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define rep1(i,a,n) for( int i=(a);i<(n);++i)
#define rep2(i,a,n) for( int i=(a);i<=(n);++i)
#define per1(i,n,a) for( int i=(n);i>(a);i--)
#define per2(i,n,a) for( int i=(n);i>=(a);i--)
#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define memset(a,i,b) memset((a),(i),sizeof (b))
#define memcpy(a,i,b) memcpy((a),(i),sizeof (b))
#define pro_q priority_queue
#define eb emplace_back
#define endl "\n"
#define lowbit(m) ((-m)&(m))
#define dbug(y) cout<<(#y)<<"\n"
#define yi first
#define er second
#define INF 0x3f3f3f3f
#define tulun int e[N],ne[N],h[N],w[N],idx;
#define add2(a,b) e[idx]=b,ne[idx]=h[a],h[a]=idx++;
#define add3(a,b,c) we[idx]=c,e[idx]=b,ne[idx]=h[a],h[a]=idx++;
#define T_solve() int T;cin>>T;while(T--)solve();
#define pi 3.14159265358979323846
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
typedef pair<pair<int,int>,pair<int,int>>PIIII;
typedef pair<long long,long long> PLL;
typedef double dob;
typedef pair<dob,dob> PDD;
const int N=1e5+10;
tulun;
int n,root;
int m;
int fa[N][17];
int d[N];
void bfs()
{
queue<int>q;
q.push(root);
memset(d,0x3f,d);
d[root]=1;
d[0]=0;
while(q.size())
{
int t=q.front();q.pop();
for(int i=h[t];~i;i=ne[i])
{
int j=e[i];
if(d[j]>d[t]+1)
{
q.push(j);
d[j]=d[t]+1;
fa[j][0]=t;
rep2(k,1,15)
{
fa[j][k]=fa[fa[j][k-1]][k-1];
}
}
}
}
}
int lca(int a,int b)
{
if(d[a]<d[b])swap(a,b);
per2(k,15,0)
if(d[fa[a][k]]>=d[b])a=fa[a][k];
if(a==b)return a;
per2(k,15,0)
if(fa[a][k]!=fa[b][k])
{
a=fa[a][k];
b=fa[b][k];
}
return fa[a][0];
}
signed main()
{
quick_cin();
memset(h,-1,h);
cin>>n;
rep2(i,1,n)
{
int a,b;
cin>>a>>b;
if(b==-1)root=a;
else
{
add2(a,b);
add2(b,a);
}
}
bfs();
cin>>m;
while(m--)
{
int a,b;
cin>>a>>b;
int p=lca(a,b);
if(p==a)dbug(1);
else if(p==b)dbug(2);
else dbug(0);
}
return 0;
}
3,树链剖分;
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define rep1(i,a,n) for( int i=(a);i<(n);++i)
#define rep2(i,a,n) for( int i=(a);i<=(n);++i)
#define per1(i,n,a) for( int i=(n);i>(a);i--)
#define per2(i,n,a) for( int i=(n);i>=(a);i--)
#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define memset(a,i,b) memset((a),(i),sizeof (b))
#define memcpy(a,i,b) memcpy((a),(i),sizeof (b))
#define pro_q priority_queue
#define eb emplace_back
#define endl "\n"
#define lowbit(m) ((-m)&(m))
#define dbug(y) cout<<(#y)<<"\n"
#define yi first
#define er second
#define INF 0x3f3f3f3f
#define tulun int e[N],ne[N],h[N],w[N],idx;
#define add2(a,b) e[idx]=b,ne[idx]=h[a],h[a]=idx++;
#define add3(a,b,c) we[idx]=c,e[idx]=b,ne[idx]=h[a],h[a]=idx++;
#define T_solve() int T;cin>>T;while(T--)solve();
#define pi 3.14159265358979323846
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
typedef pair<pair<int,int>,pair<int,int>>PIIII;
typedef pair<long long,long long> PLL;
typedef double dob;
typedef pair<dob,dob> PDD;
const int N=2e5+10;
int n,m;
tulun;
int id[N],nw[N],cnt;
int dep[N],sz[N],top[N],fa[N],son[N];
struct node
{
int l,r;
LL sum,flag;
}tr[N<<2];
void dfs1(int u,int father,int depth)
{
dep[u]=depth,fa[u]=father,sz[u]=1;
for(int i=h[u];~i;i=ne[i])
{
int j=e[i];
if(j==father)continue;
dfs1(j,u,depth+1);
sz[u]+=sz[j];
if(sz[son[u]]<sz[j])son[u]=j;
}
}
void dfs2(int u,int t)
{
id[u]=++cnt,nw[cnt]=w[u],top[u]=t;
if(!son[u])return;
dfs2(son[u],t);
for(int i=h[u];~i;i=ne[i])
{
int j=e[i];
if(j==fa[u]||j==son[u])continue;
dfs2(j,j);
}
}
void pushup(int u)
{
tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
}
void pushdown(int u)
{
auto &root =tr[u],&left=tr[u<<1],&right=tr[u<<1|1];
if(root.flag)
{
left.sum+=root.flag*(left.r-left.l+1);
left.flag+=root.flag;
right.sum+=root.flag*(right.r-right.l+1);
right.flag+=root.flag;
root.flag=0;
}
}
void build(int u,int l,int r)
{
tr[u]={l,r};
if(l==r)
{
tr[u].sum=nw[l];
return;
}
int mid=l+r>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
pushup(u);
}
void update(int u,int l,int r,int k)
{
if(l<=tr[u].l&&r>=tr[u].r)
{
tr[u].flag+=k;
tr[u].sum+=k*(tr[u].r-tr[u].l+1);
return;
}
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid)update(u<<1,l,r,k);
if(r>mid)update(u<<1|1,l,r,k);
pushup(u);
}
LL query(int u,int l,int r)
{
if(l<=tr[u].l&&r>=tr[u].r)return tr[u].sum;
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
LL res=0;
if(l<=mid)res+=query(u<<1,l,r);
if(r>mid)res+=query(u<<1|1,l,r);
return res;
}
void updat_path(int u,int v,int k)
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])swap(u,v);
update(1,id[top[u]],id[u],k);
u=fa[top[u]];
}
if(dep[u]<dep[v])swap(u,v);
update(1,id[v],id[u],k);
}
LL query_path(int u,int v)
{
LL res=0;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])swap(u,v);
res+=query(1,id[top[u]],id[u]);
u=fa[top[u]];
}
if(dep[u]<dep[v])swap(u,v);
res+=query(1,id[v],id[u]);
return res;
}
void update_tree(int u,int k)
{
update(1,id[u],id[u]+sz[u]-1,k);
}
LL query_tree(int u)
{
return query(1,id[u],id[u]+sz[u]-1);
}
signed main()
{
quick_cin();
cin>>n;
memset(h,-1,h);
rep2(i,1,n)cin>>w[i];
rep2(i,1,n-1)
{
int a,b;
cin>>a>>b;
add2(a,b);
add2(b,a);
}
dfs1(1,-1,1);
dfs2(1,1);
build(1,1,n);
cin>>m;
while(m--)
{
int t,u,v,k;
cin>>t>>u;
if(t==1)
{
cin>>v>>k;
updat_path(u,v,k);
}
else if(t==2)
{
cin>>k;
update_tree(u,k);
}
else if(t==3)
{
cin>>v;
cout<<query_path(u,v)<<endl;
}
else
{
cout<<query_tree(u)<<endl;
}
}
return 0;
}