P8360 [SNOI2022] 军队(分块+块内同颜色建树)
I_am_Accepted · · 题解
一眼看题发现 polylog 不可做(若可以请以任何方式通知我),考虑分块。
对于 1 操作想到 dsu,但是 2 操作否认了这一个想法。
我们可以将 dsu 转成二叉树,然后 2 操作打懒标记。
对于两边的散块,我们暴力拆解重构。
拆解时遍历每一棵树,下传懒标记,转成
实现要达到
对于 3 询问,我们记录每一个整块的和,散块暴力拆解
总复杂度
对于空间,发现出题人卡
既然在线空间不行则转为离线,对于每一个块分别计算答案,统计在一起即可。
空间
/*
* Author: ShaoJia
* Last Modified time: 2022-09-09 22:14:25
* Motto: We'll be counting stars.
*/
#include<bits/stdc++.h>
using namespace std;
#define For(i,j,k) for(int i=(j);i<=(k);i++)
#define Rof(i,j,k) for(int i=(j);i>=(k);i--)
#define ll long long
char buf[1<<21],*p1,*p2;
#define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
inline int read() {
int x=0,f=1;
char c=gc();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=gc();}
return x*f;
}
const int N=250002,gap=500;
struct Que{
int opt,l,r,x,y;
}Q[N];
struct node{
int ls,rs,sz,pos;
ll val;
node(){}
node(int k1,int k2,int k3,int k4,ll k5){ ls=k1,rs=k2,sz=k3,pos=k4,val=k5; }
}t[gap<<1];
int n,q,C,c[N],lim,L,R,tot,root[N],s[N],st;
ll a[N],ans[N],sum;
bool vis[N];
inline int merge(int x,int y){
if(!x || !y) return x^y;
t[++tot]=node(x,y,t[x].sz+t[y].sz,0,0);
return tot;
}
void build(){
sum=0;
For(i,L,R){
t[++tot]=node(0,0,1,i,a[i]);
if(!vis[c[i]]){
vis[c[i]]=true;
s[++st]=c[i];
root[c[i]]=tot;
}else{
root[c[i]]=merge(tot,root[c[i]]);
}
sum+=a[i];
}
}
inline void dfs(int rt,int col){
if(!t[rt].ls){
a[t[rt].pos]=t[rt].val;
c[t[rt].pos]=col;
return ;
}
int ls=t[rt].ls,rs=t[rt].rs;
t[ls].val+=t[rt].val;
t[rs].val+=t[rt].val;
dfs(ls,col);
dfs(rs,col);
}
void ruin(){
For(i,1,st){
if(root[s[i]]){
dfs(root[s[i]],s[i]);
root[s[i]]=0;
}
}
For(i,1,st)
vis[s[i]]=false;
st=tot=0;
}
void Chan(int x,int y){
if(!root[x] || x==y) return ;
root[y]=merge(root[y],root[x]);
root[x]=0;
if(!vis[y]){//!!!
s[++st]=y;
vis[y]=true;
}
}
void chan(int l,int r,int x,int y){
ruin();
For(i,l,r) if(c[i]==x) c[i]=y;
build();
}
void Add(int x,ll y){
if(root[x]){
t[root[x]].val+=y;
sum+=t[root[x]].sz*y;
}
}
void add(int l,int r,int x,ll y){
ruin();
For(i,l,r) if(c[i]==x) a[i]+=y;
build();
}
ll que(int l,int r){
ruin();
ll res=0;
For(i,l,r) res+=a[i];
build();
return res;
}
void solve(){
tot=0;
build();
int l,r;
For(i,1,q){
l=max(Q[i].l,L);
r=min(Q[i].r,R);
if(l>r) continue;
if(L==l && R==r){//all
if(Q[i].opt==1) Chan(Q[i].x,Q[i].y);
else if(Q[i].opt==2) Add(Q[i].x,Q[i].y);
else ans[i]+=sum;
}else{//some
if(Q[i].opt==1) chan(l,r,Q[i].x,Q[i].y);
else if(Q[i].opt==2) add(l,r,Q[i].x,Q[i].y);
else ans[i]+=que(l,r);
}
}
ruin();
}
signed main(){
n=read(),q=read(),C=read();
For(i,1,n) a[i]=read();
For(i,1,n) c[i]=read();
lim=(n-1)/gap+1;
For(i,1,q){
Q[i].opt=read(),Q[i].l=read(),Q[i].r=read();
if(Q[i].opt!=3) Q[i].x=read(),Q[i].y=read();
}
For(i,1,lim) L=1+(i-1)*gap,R=min(i*gap,n),solve();
For(i,1,q) if(Q[i].opt==3) printf("%lld\n",ans[i]);
return 0;}