⬜ 代码总结

思路

  1. 先离线储存,取块长。

  2. 记录 \(to\) 表示当前指向,\(a\) 表示 数值。

  3. 对于每个块

  • 先对于现有的 \(to,a\) 建树,显然以 \(to_i=i\)\(i\) 为根,并预处理前缀和 \(s\)
  • 记录关键点:1 操作的 \(x\),2 操作的 \(x,y\),并去重,且标记所有关键点。
  • 从每个关键点跑出修改序列,注意若关键点 \(u\) 包含关键点 \(v\) 则修改序列不包括 \(v\) 的子树。别忘了修改序列要排序,并记录修改序列前缀和。在 dfs 的时候用 \(fa\) 记录关键点之间的父子关系,用 set 记录边。
  • 然后开始遍历每个操作,把修改了的关键点记录下来并修改 \(to\),其他具体细节看代码。
  • 对于询问,先遍历修改了的关键点并修改 \(a\)(不修改 \(s\)),然后先 \(ans=s_r-s_{l-1}\),然后对于所有关键点二分出询问的区间 \(L,R\),把原贡献减去,把现贡献加上。
  • 最后别忘了再遍历修改了的关键点并修改 \(a\),还有清空图和标记。

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
    char ch=getchar();int x=0;bool f=1;
    while(ch<'0'||'9'<ch){if(ch=='-')f=0;ch=getchar();}
    while('0'<=ch&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return f?x:-x;
}
const int N=1e5+2,B=1288;
int n,m,a[N],s[N],to[N],fa[N];
struct node{
    int opt,x,y;
}q[N];
vector<int>G[N],vt[N],st[N];
bool vis[N],ok[N];
void init(int u){
    for(int v:G[u])a[v]=a[u],init(v);
}
void dfs(int u,int rt){
    vt[rt].push_back(u);
    for(int v:G[u]){fa[v]=rt;if(!vis[v])dfs(v,rt);}
}
set<int>E[N],Et;
signed main(){
    // freopen(".in","r",stdin);
    // freopen(".out","w",stdout);
    n=read();m=read();
    for(int i=1;i<=n;i++)a[i]=read(),to[i]=i;
    for(int i=1;i<=m;i++)q[i]={read(),read(),read()};
    for(int l=1,r;l<=m;l=r+1){
        vector<int>nod;
        r=min(m,l+B-1);
        Et.clear();
        for(int i=1;i<=n;i++)G[i].clear(),fa[i]=i,E[i].clear();
        for(int i=1;i<=n;i++)if(to[i]!=i)G[to[i]].push_back(i);
        for(int i=1;i<=n;i++)if(to[i]==i)init(i);
        for(int i=1;i<=n;i++)s[i]=s[i-1]+a[i];
        for(int i=l;i<=r;i++)
            if(q[i].opt==1)vis[q[i].x]=1,nod.push_back(q[i].x);
            else if(q[i].opt==2)vis[q[i].x]=1,vis[q[i].y]=1,nod.push_back(q[i].x),nod.push_back(q[i].y);
        sort(nod.begin(),nod.end());
        nod.erase(unique(nod.begin(),nod.end()),nod.end());
        for(int x:nod){
            dfs(x,x),sort(vt[x].begin(),vt[x].end());
            st[x].push_back(a[vt[x].front()]);
            for(int j=1;j<(int)vt[x].size();j++)
                st[x].push_back(st[x].back()+a[vt[x][j]]);
        }
        for(int x:nod)if(fa[x]!=x)E[fa[x]].insert(x);
        for(int T=l;T<=r;T++)
            if(q[T].opt==1){
                to[q[T].x]=q[T].x;
                E[fa[q[T].x]].erase(q[T].x);
                a[q[T].x]=q[T].y;fa[q[T].x]=q[T].x;
                Et.insert(q[T].x);
            }
            else if(q[T].opt==2){
                to[q[T].x]=q[T].y;
                E[fa[q[T].x]].erase(q[T].x);
                fa[q[T].x]=q[T].y;
                E[fa[q[T].x]].insert(q[T].x);
                Et.insert(fa[q[T].x]);
            }
            else{
                int ans=s[q[T].y]-s[q[T].x-1];
                queue<int>Q;
                for(int i:Et)Q.push(i);
                Et.clear();
                while(!Q.empty()){
                    int u=Q.front();Q.pop();
                    for(int v:E[u])a[v]=a[u],Q.push(v);
                }
                for(int x:nod){
                    int L=lower_bound(vt[x].begin(),vt[x].end(),q[T].x)-vt[x].begin();
                    int R=upper_bound(vt[x].begin(),vt[x].end(),q[T].y)-vt[x].begin()-1;
                    if(L<=R){
                        ans-=st[x][R]-(L?st[x][L-1]:0);
                        ans+=(R-L+1)*a[x];
                    }
                }
                printf("%lld\n",ans);
            }
        queue<int>Q;
        for(int i:Et)Q.push(i);
        Et.clear();
        while(!Q.empty()){
            int u=Q.front();Q.pop();
            for(int v:E[u])a[v]=a[u],Q.push(v);
        }
        for(int i=l;i<=r;i++)ok[i]=0;
        for(int i=1;i<=n;i++)vt[i].clear(),st[i].clear(),vis[i]=0;
    }
    return 0;
}
posted @ 2024-11-21 22:01  sunzz3183  阅读(27)  评论(0编辑  收藏  举报
Live2D