22/7/21

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dull丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值