树状数组
树状数组1
题意:单点修改,求前缀和
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 2e5+10;
ll a[N],c[N];
int n;
inline int lowbit(int x) {return x&-x;}
inline void update(int x,ll a) {while(x<=n) c[x]+=a,x+=lowbit(x);}
inline ll query(int x) {ll res = 0;while(x) res+=c[x],x-=lowbit(x);return res;}
void solve()
{
int q;
cin>>n>>q;
for(int i=1;i<=n;++i)
{
cin>>a[i];
update(i,a[i]);
}
for(int i=1;i<=q;++i)
{
int op;
cin>>op;
if(op&1)
{
int x,d;
cin>>x>>d;
update(x,d-a[x]);
a[x] = d;
}
else
{
int x;
cin>>x;
cout<<query(x)<<'\n';
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T=1;
while(T--)
{
solve();
}
}
树状数组2(bushi)
题意:区间改,区间查
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 2e5+10;
int a[N];
int n,q;
struct node
{
int l,r;
ll sum,lazy;
}tr[N<<2];
void pushup(int p)
{
tr[p].sum = tr[p<<1].sum+tr[p<<1|1].sum;
}
void pushdown(int p)
{
if(!tr[p].lazy) return ;
int l = tr[p].l, r = tr[p].r, m = l+(r-l)/2;
ll lazy = tr[p].lazy;
tr[p<<1].sum += lazy*(m-l+1);
tr[p<<1|1].sum += lazy*(r-m);
tr[p<<1].lazy += lazy;
tr[p<<1|1].lazy +=lazy;
tr[p].lazy = 0;
}
void build(int l,int r,int p)
{
tr[p].l = l,tr[p].r = r;
if(l==r)
{
tr[p].sum = a[l];
return ;
}
int m = l+(r-l)/2;
build(l,m,p<<1);
build(m+1,r,p<<1|1);
pushup(p);
}
void update(int x,int y,int p,ll d)
{
int l = tr[p].l, r = tr[p].r;
if(x<=l&&r<=y)
{
tr[p].sum += d*(r-l+1);
tr[p].lazy+=d;
return ;
}
pushdown(p);
int m = l+(r-l)/2;
if(x<=m) update(x,y,p<<1,d);
if(y>m) update(x,y,p<<1|1,d);
pushup(p);
}
ll query(int x,int y,int p)
{
int l = tr[p].l, r = tr[p].r;
if(x>r||l>y) return 0;
if(x<=l&&r<=y) return tr[p].sum;
pushdown(p);
return query(x,y,p<<1)+query(x,y,p<<1|1);
}
void solve()
{
cin>>n>>q;
build(1,n,1);
for(int i=1;i<=q;++i)
{
int op;
cin>>op;
if(op&1)
{
int l,r,d;
cin>>l>>r>>d;
update(l,r,1,d);
}
else
{
int x;
cin>>x;
cout<<query(1,x,1)<<'\n';
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T=1;
while(T--)
{
solve();
}
}
逆序对
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 100010;
int c[N];
int n;
inline int lowbit(int x) {return x&-x;}
inline void update(int x,int d) {while(x<=n) c[x]+=d,x+=lowbit(x);}
inline ll sum(int x) {ll res = 0;while(x) res+=c[x],x-=lowbit(x);return res;}
void solve()
{
cin>>n;
ll ans = 0;
for(int i=1;i<=n;++i)
{
int x;
cin>>x;
update(x,1);
ans+=sum(n)-sum(x);
}
cout<<ans<<'\n';
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T=1;
while(T--)
{
solve();
}
}
树状数组二分
题意:1.修改a[x] = d,2.输入s,求最大的T,使得<=s
解析:从高位向低位枚举,根据树状数组定义f(i) = 类似倍增当pos'变成pos时,t增加了c[pos'+1]~c[pos],最终确定位置T
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 2e5+10;
ll a[N],c[N];
int n,q;
inline int lowbit(int x) {return x&-x;}
inline void update(int x,int d) {while(x<=n) c[x]+=d,x+=lowbit(x);}
inline int log_2(ll x) {return 63-__builtin_clzll(x);}
inline int query(ll s)
{
int x = log_2(n)+1;
ll t = 0, pos = 0;
for(int j=x;j>=0;--j)
{
if(pos+(1<<j)<=n&&t+c[pos+(1<<j)]<=s)
{
t+=c[pos+(1<<j)];
pos+=(1<<j);
}
}
return pos;
}
void solve()
{
cin>>n>>q;
for(int i=1;i<=n;++i)
{
cin>>a[i];
update(i,a[i]);
}
for(int i=1;i<=q;++i)
{
int op;
cin>>op;
if(op&1)
{
int x,d;
cin>>x>>d;
update(x,d-a[x]);
a[x] = d;
}
else
{
ll s;
cin>>s;
cout<<query(s)<<'\n';
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T=1;
while(T--)
{
solve();
}
}
二维数组数组
题意:1.修改a[x][y] = d 2.查询
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 501;
ll a[N][N],c[N][N];
int n,m,q;
inline int lowbit(int x) {return x&-x;}
inline void update(int x,int y,int d)
{
for(int p=x;p<=n;p+=lowbit(p))
for(int q=y;q<=m;q+=lowbit(q))
c[p][q]+=d;
}
inline ll query(int x,int y)
{
ll res = 0;
for(int p=x;p;p-=lowbit(p))
for(int q=y;q;q-=lowbit(q))
res+=c[p][q];
return res;
}
void solve()
{
cin>>n>>m>>q;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
{
cin>>a[i][j];
update(i,j,a[i][j]);
}
for(int i=1;i<=q;++i)
{
int op;
cin>>op;
if(op&1)
{
int x,y,d;
cin>>x>>y>>d;
update(x,y,d-a[x][y]);
a[x][y] = d;
}
else
{
int x,y;
cin>>x>>y;
cout<<query(x,y)<<'\n';
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T=1;
while(T--)
{
solve();
}
}
线段树
线段树1
题意:1.修改a[x] = d。2.查询l~r的最小值及其出现次数
给出封装化线段树
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 2e5+10;
int n,q;
int a[N];
struct info
{
int minn,mincnt;
};
info operator + (const info& l,const info& r)
{
info a;
a.minn = min(l.minn,r.minn);
if(l.minn==r.minn) a.mincnt = l.mincnt+r.mincnt;
else if(l.minn<r.minn) a.mincnt = l.mincnt;
else a.mincnt = r.mincnt;
return a;
}
struct node
{
int l,r;
info val;
}tr[N<<2];
void pushup(int p)
{
tr[p].val = tr[p<<1].val + tr[p<<1|1].val;
}
void build(int l,int r,int p)
{
tr[p].l = l,tr[p].r = r;
if(l==r)
{
tr[p].val = {a[l],1};
return ;
}
int m = (l+r)/2;
build(l,m,p<<1);
build(m+1,r,p<<1|1);
pushup(p);
}
void update(int x,int d,int p)
{
int l = tr[p].l, r = tr[p].r;
if(l==r)
{
tr[p].val = {d,1};
return ;
}
int m = (l+r)/2;
if(x<=m) update(x,d,p<<1);
else update(x,d,p<<1|1);
pushup(p);
}
info query(int x,int y,int p)
{
int l = tr[p].l,r = tr[p].r;
if(x==l&&r==y) return tr[p].val;
info ans;
int m = (l+r)/2;
if(y<=m) return query(x,y,p<<1);
else if(x>m) return query(x,y,p<<1|1);
else return query(x,m,p<<1)+query(m+1,y,p<<1|1);
}
void solve()
{
cin>>n>>q;
for(int i=1;i<=n;++i) cin>>a[i];
build(1,n,1);
for(int i=1;i<=q;++i)
{
int op;
cin>>op;
if(op&1)
{
int x,d;
cin>>x>>d;
update(x,d,1);
}
else
{
int x,y;
cin>>x>>y;
auto res = query(x,y,1);
cout<<res.minn<<" "<<res.mincnt<<'\n';
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T=1;
while(T--)
{
solve();
}
}
线段树2
题意:1.修改a[x] = d 2.查询[l,r]的最大子段和
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 2e5+10;
int n,q;
int a[N];
struct info
{
ll mms,mpre,msuf,sum;
info() {}
info(int a) :mms(a),mpre(a),msuf(a),sum(a) {}
};
info operator + (const info& l,const info& r)
{
info a;
a.mms = max({l.mms,r.mms,l.msuf+r.mpre});
a.mpre = max(l.mpre,l.sum+r.mpre);
a.msuf = max(r.msuf,l.msuf+r.sum);
a.sum = l.sum + r.sum;
return a;
}
struct node
{
int l,r;
info val;
}tr[N<<2];
void pushup(int p)
{
tr[p].val = tr[p<<1].val + tr[p<<1|1].val;
}
void build(int l,int r,int p)
{
tr[p].l = l,tr[p].r = r;
if(l==r)
{
tr[p].val = info(a[l]);
return ;
}
int m = (l+r)/2;
build(l,m,p<<1);
build(m+1,r,p<<1|1);
pushup(p);
}
void update(int x,int d,int p)
{
int l = tr[p].l, r = tr[p].r;
if(l==r)
{
tr[p].val = info(d);
return ;
}
int m = (l+r)/2;
if(x<=m) update(x,d,p<<1);
else update(x,d,p<<1|1);
pushup(p);
}
info query(int x,int y,int p)
{
int l = tr[p].l,r = tr[p].r;
if(x==l&&r==y) return tr[p].val;
info ans;
int m = (l+r)/2;
if(y<=m) return query(x,y,p<<1);
else if(x>m) return query(x,y,p<<1|1);
else return query(x,m,p<<1)+query(m+1,y,p<<1|1);
}
void solve()
{
cin>>n>>q;
for(int i=1;i<=n;++i) cin>>a[i];
build(1,n,1);
for(int i=1;i<=q;++i)
{
int op;
cin>>op;
if(op&1)
{
int x,d;
cin>>x>>d;
update(x,d,1);
}
else
{
int x,y;
cin>>x>>y;
auto res = query(x,y,1);
cout<<res.mms<<'\n';
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T=1;
while(T--)
{
solve();
}
}
线段树打标记1
题意:1.将[l,r]加上d 2.求[l,r]的max
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 2e5+10;
int n,q;
int a[N];
struct info
{
ll maxn;
info() {}
info(int a) :maxn(a) {}
};
struct tag
{
ll add;
};
info operator + (const info& l,const info& r)
{
info a;
a.maxn = max(l.maxn , r.maxn);
return a;
}
info operator + (const info &v,const tag& t)
{
info a;
a.maxn = v.maxn + t.add;
return a;
}
tag operator + (const tag &t1,const tag&t2)
{
tag t;
t.add = t1.add + t2.add;
return t;
}
struct node
{
int l,r;
info val;
tag t;
}tr[N<<2];
void settag(int p,tag t)
{
tr[p].val = tr[p].val + t;
tr[p].t = tr[p].t + t;
}
void pushup(int p)
{
tr[p].val = tr[p<<1].val + tr[p<<1|1].val;
}
void pushdown(int p)
{
if(tr[p].t.add!=0)
{
settag(p<<1,tr[p].t);
settag(p<<1|1,tr[p].t);
tr[p].t.add = 0;
}
}
void build(int l,int r,int p)
{
tr[p].l = l,tr[p].r = r;
if(l==r)
{
tr[p].val = info(a[l]);
return ;
}
int m = (l+r)/2;
build(l,m,p<<1);
build(m+1,r,p<<1|1);
pushup(p);
}
void update(int x,int y,tag C,int p)
{
int l = tr[p].l, r = tr[p].r;
if(l==x&&r==y)
{
settag(p,C);
return ;
}
pushdown(p);
int m = (l+r)/2;
if(y<=m) update(x,y,C,p<<1);
else if(x>m) update(x,y,C,p<<1|1);
else
{
update(x,m,C,p<<1);
update(m+1,y,C,p<<1|1);
}
pushup(p);
}
info query(int x,int y,int p)
{
int l = tr[p].l,r = tr[p].r;
if(x==l&&r==y) return tr[p].val;
pushdown(p);
info ans;
int m = (l+r)/2;
if(y<=m) return query(x,y,p<<1);
else if(x>m) return query(x,y,p<<1|1);
else return query(x,m,p<<1)+query(m+1,y,p<<1|1);
}
void solve()
{
cin>>n>>q;
for(int i=1;i<=n;++i) cin>>a[i];
build(1,n,1);
for(int i=1;i<=q;++i)
{
int op;
cin>>op;
if(op&1)
{
int x,y,C;
cin>>x>>y>>C;
update(x,y,(tag){C},1);
}
else
{
int x,y;
cin>>x>>y;
auto res = query(x,y,1);
cout<<res.maxn<<'\n';
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T=1;
while(T--)
{
solve();
}
}
线段树打标记2
题意:1.[l,r]加d 2.[l,r]乘d 3.[l,r]等于d 4.查询[l,r]
非结构化写法
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 2e5+10;
int n,q;
int a[N];
const int mod = 1e9+7;
struct tag
{
ll mul,add;
tag():mul(1),add(0) {}
tag(ll a,ll b):mul(a),add(b) {}
};
tag operator + (const tag &t1,const tag&t2)
{
tag t;
t.mul = t1.mul*t2.mul%mod;
t.add = (t1.mul*t2.add%mod + t1.add)%mod;
return t;
}
struct node
{
int l,r;
ll sum,sz;
tag t;
}tr[N<<2];
void settag(int p,tag t)
{
tr[p].sum = (t.mul*tr[p].sum%mod + t.add*tr[p].sz%mod)%mod;
tr[p].t = t + tr[p].t;
}
void pushup(int p)
{
tr[p].sum = (tr[p<<1].sum + tr[p<<1|1].sum)%mod;
}
void pushdown(int p)
{
if(tr[p].t.mul!=1||tr[p].t.add!=0)
{
settag(p<<1,tr[p].t);
settag(p<<1|1,tr[p].t);
tr[p].t.mul = 1;
tr[p].t.add = 0;
}
}
void build(int l,int r,int p)
{
tr[p].l = l,tr[p].r = r,tr[p].sz = r-l+1;
if(l==r)
{
tr[p].sum = a[l];
return ;
}
int m = (l+r)/2;
build(l,m,p<<1);
build(m+1,r,p<<1|1);
pushup(p);
}
void update(int x,int y,tag C,int p)
{
int l = tr[p].l, r = tr[p].r;
if(l==x&&r==y)
{
settag(p,C);
return ;
}
pushdown(p);
int m = (l+r)/2;
if(y<=m) update(x,y,C,p<<1);
else if(x>m) update(x,y,C,p<<1|1);
else
{
update(x,m,C,p<<1);
update(m+1,y,C,p<<1|1);
}
pushup(p);
}
ll query(int x,int y,int p)
{
int l = tr[p].l,r = tr[p].r;
if(x==l&&r==y) return tr[p].sum;
pushdown(p);
int m = (l+r)/2;
if(y<=m) return query(x,y,p<<1);
else if(x>m) return query(x,y,p<<1|1);
else return (query(x,m,p<<1)+query(m+1,y,p<<1|1))%mod;
}
void solve()
{
cin>>n>>q;
for(int i=1;i<=n;++i) cin>>a[i];
build(1,n,1);
for(int i=1;i<=q;++i)
{
int op;
cin>>op;
if(op==1)
{
int x,y,d;
cin>>x>>y>>d;
update(x,y,tag(1,d),1);
}
else if(op==2)
{
int x,y,d;
cin>>x>>y>>d;
update(x,y,tag(d,0),1);
}
else if(op==3)
{
int x,y,d;
cin>>x>>y>>d;
update(x,y,tag(0,d),1);
}
else
{
int x,y;
cin>>x>>y;
ll res = query(x,y,1);
cout<<res<<'\n';
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T=1;
while(T--)
{
solve();
}
}
结构化写法
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 2e5+10;
int n,q;
int a[N];
const int mod = 1e9+7;
struct info
{
ll sum,sz;
info() {}
info(ll a) :sum(a),sz(1) {}
};
struct tag
{
ll mul,add;
tag():mul(1),add(0) {}
tag(ll a,ll b):mul(a),add(b) {}
};
info operator + (const info& l,const info& r)
{
info a;
a.sum = (l.sum+r.sum)%mod;
a.sz = l.sz+r.sz;
return a;
}
info operator + (const info &v,const tag& t)
{
info a;
a.sum = (v.sum*t.mul%mod + t.add*v.sz%mod)%mod;
a.sz = v.sz;
return a;
}
tag operator + (const tag &t1,const tag&t2)
{
tag t;
t.mul = t1.mul*t2.mul%mod;
t.add = (t1.mul*t2.add%mod + t1.add)%mod;
return t;
}
struct node
{
int l,r;
info val;
tag t;
}tr[N<<2];
void settag(int p,tag t)
{
tr[p].val = tr[p].val + t;
tr[p].t = t + tr[p].t;
}
void pushup(int p)
{
tr[p].val = tr[p<<1].val + tr[p<<1|1].val;
}
void pushdown(int p)
{
if(tr[p].t.add!=0||tr[p].t.mul!=1)
{
settag(p<<1,tr[p].t);
settag(p<<1|1,tr[p].t);
tr[p].t.add = 0;
tr[p].t.mul = 1;
}
}
void build(int l,int r,int p)
{
tr[p].l = l,tr[p].r = r;
if(l==r)
{
tr[p].val = info(a[l]);
return ;
}
int m = (l+r)/2;
build(l,m,p<<1);
build(m+1,r,p<<1|1);
pushup(p);
}
void update(int x,int y,tag C,int p)
{
int l = tr[p].l, r = tr[p].r;
if(l==x&&r==y)
{
settag(p,C);
return ;
}
pushdown(p);
int m = (l+r)/2;
if(y<=m) update(x,y,C,p<<1);
else if(x>m) update(x,y,C,p<<1|1);
else
{
update(x,m,C,p<<1);
update(m+1,y,C,p<<1|1);
}
pushup(p);
}
info query(int x,int y,int p)
{
int l = tr[p].l,r = tr[p].r;
if(x==l&&r==y) return tr[p].val;
pushdown(p);
info ans;
int m = (l+r)/2;
if(y<=m) return query(x,y,p<<1);
else if(x>m) return query(x,y,p<<1|1);
else return query(x,m,p<<1)+query(m+1,y,p<<1|1);
}
void solve()
{
cin>>n>>q;
for(int i=1;i<=n;++i) cin>>a[i];
build(1,n,1);
for(int i=1;i<=q;++i)
{
int op;
cin>>op;
if(op==1)
{
int x,y,d;
cin>>x>>y>>d;
update(x,y,tag(1,d),1);
}
else if(op==2)
{
int x,y,d;
cin>>x>>y>>d;
update(x,y,tag(d,0),1);
}
else if(op==3)
{
int x,y,d;
cin>>x>>y>>d;
update(x,y,tag(0,d),1);
}
else
{
int x,y;
cin>>x>>y;
auto res = query(x,y,1);
cout<<res.sum<<'\n';
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T=1;
while(T--)
{
solve();
}
}
线段树上二分
题意:1.a[x] = d 2.求[l,r]第一个>=d的下标
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 2e5+10;
int n,q;
int a[N];
struct info
{
int maxn;
};
info operator + (const info& l,const info& r)
{
info a;
a.maxn = max(l.maxn,r.maxn);
return a;
}
struct node
{
int l,r;
info val;
}tr[N<<2];
void pushup(int p)
{
tr[p].val = tr[p<<1].val + tr[p<<1|1].val;
}
void build(int l,int r,int p)
{
tr[p].l = l,tr[p].r = r;
if(l==r)
{
tr[p].val = {a[l]};
return ;
}
int m = (l+r)/2;
build(l,m,p<<1);
build(m+1,r,p<<1|1);
pushup(p);
}
void update(int x,int d,int p)
{
int l = tr[p].l, r = tr[p].r;
if(l==r)
{
tr[p].val = {d};
return ;
}
int m = (l+r)/2;
if(x<=m) update(x,d,p<<1);
else update(x,d,p<<1|1);
pushup(p);
}
int search(int x,int y,int d,int p)
{
int l = tr[p].l,r = tr[p].r;
int m = (l+r)/2;
if(l==x&&y==r)
{
if(tr[p].val.maxn < d) return -1;
if(l==r) return l;
if(tr[p<<1].val.maxn>=d) return search(x,m,d,p<<1);
else return search(m+1,y,d,p<<1|1);
}
if(y<=m) return search(x,y,d,p<<1);
else if(x>m) return search(x,y,d,p<<1|1);
else
{
int tmp = search(x,m,d,p<<1);
if(tmp!=-1) return tmp;
else return search(m+1,y,d,p<<1|1);
}
}
void solve()
{
cin>>n>>q;
for(int i=1;i<=n;++i) cin>>a[i];
build(1,n,1);
for(int i=1;i<=q;++i)
{
int op;
cin>>op;
if(op&1)
{
int x,d;
cin>>x>>d;
update(x,d,1);
}
else
{
int x,y,d;
cin>>x>>y>>d;
int res = search(x,y,d,1);
cout<<res<<'\n';
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T=1;
while(T--)
{
solve();
}
}
扫描线
二维数点
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
vector<array<int,4>> event;
vector<int> vx;
const int N = 2e5+10;
int m;
int c[N*2],ans[N];
inline int lowbit(int x) {return x&-x;}
inline void update(int x,int y) {while(x<=m) c[x]+=y,x+=lowbit(x);}
inline ll sum(int x) {ll res=0;while(x) res+=c[x],x-=lowbit(x);return res;}
int mp(int x)
{
return upper_bound(vx.begin(),vx.end(),x) - vx.begin() ;
};
void solve()
{
int n,q;
cin>>n>>q;
for(int i=0;i<n;++i)
{
int x,y;
cin>>x>>y;
vx.push_back(x);
event.push_back({y,0,x});
}
for(int i=1;i<=q;++i)
{
int x1,x2,y1,y2;
cin>>x1>>x2>>y1>>y2;
event.push_back({y2,2,x2,i});
event.push_back({y1-1,2,x1-1,i});
event.push_back({y2,1,x1-1,i});
event.push_back({y1-1,1,x2,i});
}
sort(event.begin(),event.end());
sort(vx.begin(),vx.end());
vx.erase(unique(vx.begin(),vx.end()),vx.end());
m = vx.size();
for(auto evt:event)
{
int pos = mp(evt[2]);
if(!evt[1]) {update(pos,1);}
else
{
int tmp = sum(pos);
if(evt[1]==1) ans[evt[3]]-=tmp;
else ans[evt[3]]+=tmp;
}
}
for(int i=1;i<=n;++i) cout<<ans[i]<<'\n';
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T=1;
while(T--)
{
solve();
}
}
区间不同数之和
思路一:转化为二维数点,pre[i]表示i上一次出现的位置,查找的点为L<= i <= R, pre[i] < L 的点值和
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
vector<array<int,4>> event;
vector<int> vx;
const int N = 2e5+10;
int m;
ll c[N*2],ans[N];
inline int lowbit(int x) {return x&-x;}
inline void update(int x,int y) {while(x<=m) c[x]+=y,x+=lowbit(x);}
inline ll sum(int x) {ll res=0;while(x) res+=c[x],x-=lowbit(x);return res;}
int last[N],pre[N];
void solve()
{
int n,q;
cin>>n>>q;
memset(last,-1,sizeof last);
for(int i=1;i<=n;++i)
{
int a;
cin>>a;
pre[i] = last[a];
last[a] = i;
event.push_back({pre[i],0,i,a});
}
for(int i=1;i<=q;++i)
{
int l,r;
cin>>l>>r;
event.push_back({l-1,2,r,i});
event.push_back({l-1,1,l-1,i});
}
sort(event.begin(),event.end());
m = n;
for(auto evt:event)
{
int pos = evt[2];
if(!evt[1]) update(pos,evt[3]);
else
{
ll tmp = sum(pos);
if(evt[1]==1) ans[evt[3]]-=tmp;
else ans[evt[3]]+=tmp;
}
}
for(int i=1;i<=n;++i) cout<<ans[i]<<'\n';
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T=1;
while(T--)
{
solve();
}
}
思路二 : 枚举r,维护ans[l]表示[l,r]的答案,当r从r-1转移到r时,只有pos[r]<i 的区间需要增加
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 2e5+10;
int m;
ll c[N*2],ans[N];
inline int lowbit(int x) {return x&-x;}
inline void update(int x,int y) {while(x<=m) c[x]+=y,x+=lowbit(x);}
inline ll sum(int x) {ll res=0;while(x) res+=c[x],x-=lowbit(x);return res;}
int last[N],pre[N],a[N];
vector<PII> qu[N];
void solve()
{
int n,q;
cin>>n>>q;
for(int i=1;i<=n;++i)
{
cin>>a[i];
pre[i] = last[a[i]];
last[a[i]] = i;
}
for(int i=1;i<=q;++i)
{
int l,r;
cin>>l>>r;
qu[r].push_back({l,i});
}
m = n;
for(int r=1;r<=n;++r)
{
int p = pre[r];
update(p+1,a[r]);
update(r+1,-a[r]);
for(auto t:qu[r])
{
ans[t.y] = sum(t.x);
}
}
for(int i=1;i<=q;++i) cout<<ans[i]<<'\n';
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T=1;
while(T--)
{
solve();
}
}
矩形面积并
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
vector<array<int,4>> event;
const int N = 2e5+10;
vector<int> vx;
struct info
{
int minn,mincnt;
info() {}
info(int a,int x) :minn(a), mincnt(x) {}
};
struct tag
{
ll add;
};
info operator + (const info& l,const info& r)
{
info a;
a.minn = min(l.minn,r.minn);
if(l.minn==r.minn) a.mincnt = l.mincnt+r.mincnt;
else if(l.minn<r.minn) a.mincnt = l.mincnt;
else a.mincnt = r.mincnt;
return a;
}
info operator + (const info &v,const tag& t)
{
info a = v;
a.minn = v.minn + t.add;
return a;
}
tag operator + (const tag &t1,const tag&t2)
{
tag t;
t.add = t1.add + t2.add;
return t;
}
struct node
{
int l,r;
info val;
tag t;
}tr[N<<4];
void settag(int p,tag t)
{
tr[p].val = tr[p].val + t;
tr[p].t = tr[p].t + t;
}
void pushup(int p)
{
tr[p].val = tr[p<<1].val + tr[p<<1|1].val;
}
void pushdown(int p)
{
if(tr[p].t.add!=0)
{
settag(p<<1,tr[p].t);
settag(p<<1|1,tr[p].t);
tr[p].t.add = 0;
}
}
void build(int l,int r,int p)
{
tr[p].l = l,tr[p].r = r;
if(l==r)
{
tr[p].val = info(0,vx[l]-vx[l-1]);
return ;
}
int m = (l+r)/2;
build(l,m,p<<1);
build(m+1,r,p<<1|1);
pushup(p);
}
void update(int x,int y,tag C,int p)
{
int l = tr[p].l, r = tr[p].r;
if(l==x&&r==y)
{
settag(p,C);
return ;
}
pushdown(p);
int m = (l+r)/2;
if(y<=m) update(x,y,C,p<<1);
else if(x>m) update(x,y,C,p<<1|1);
else
{
update(x,m,C,p<<1);
update(m+1,y,C,p<<1|1);
}
pushup(p);
}
int m;
void divide()
{
sort(vx.begin(),vx.end());
vx.erase(unique(vx.begin(),vx.end()),vx.end());
}
int mp(int x)
{
return upper_bound(vx.begin(),vx.end(),x)-vx.begin();
}
void solve()
{
int n;
cin>>n;
for(int i=1;i<=n;++i)
{
int x1,x2,y1,y2;
cin>>x1>>x2>>y1>>y2;
vx.push_back(x1);
vx.push_back(x2);
event.push_back({y1,1,x1,x2});
event.push_back({y2,-1,x1,x2});
}
divide();
m = vx.size()-1;
build(1,m,1);
sort(event.begin(),event.end());
int totlen = tr[1].val.mincnt;
ll ans = 0;
int prey = 0;
for(auto evt:event)
{
int cov = totlen;
int x1 = mp(evt[2]),x2 = mp(evt[3])-1;
if(x1>x2) continue;
if(!tr[1].val.minn)
{
cov -= tr[1].val.mincnt;
}
ans += (ll)cov*(evt[0]-prey);
prey = evt[0];
update(x1,x2,(tag){evt[1]},1);
}
cout<<ans<<'\n';
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T=1;
while(T--)
{
solve();
}
}
权值线段树(特值bit建树)
异或第k小
题意 :给定n个数,q次询问,每次给x,k,查询a[i]^x的第k小
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 2e5+10,M = 31;
struct node
{
int s[2];
int sz;
}tr[N*32];
void solve()
{
int root = 0,tot = 0;
root = ++tot;
int n,m;
cin>>n>>m;
for(int i=1;i<=n;++i)
{
int x;
cin>>x;
int p = root;
for(int j=M;j>=0;--j)
{
tr[p].sz++;
int w = (x>>j)&1;
if(!tr[p].s[w]) tr[p].s[w] = ++tot;
p = tr[p].s[w];
}
tr[p].sz++;
}
for(int i=0;i<m;++i)
{
int x,k;
cin>>x>>k;
int p = root;
int ans = 0;
for(int j=M;j>=0;--j)
{
int w = (x>>j)&1;
if(tr[tr[p].s[w]].sz>=k)
{
p = tr[p].s[w];
}
else
{
k -= tr[tr[p].s[w]].sz;
ans ^= (1<<j);
p = tr[p].s[w^1];
}
}
cout<<ans<<'\n';
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T=1;
while(T--)
{
solve();
}
}
mex
求[l,r]的mex值
枚举r,更新pos[a[r]],线段树上二分寻找下标最小的x使得pos[x]<l
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 2e5+10;
int n,q;
int a[N];
struct info
{
int minn;
};
info operator + (const info& l,const info& r)
{
info a;
a.minn = min(l.minn,r.minn);
return a;
}
struct node
{
int l,r;
info val;
}tr[N<<2];
void pushup(int p)
{
tr[p].val = tr[p<<1].val + tr[p<<1|1].val;
}
void build(int l,int r,int p)
{
tr[p].l = l,tr[p].r = r;
if(l==r)
{
tr[p].val = {0};
return ;
}
int m = (l+r)/2;
build(l,m,p<<1);
build(m+1,r,p<<1|1);
pushup(p);
}
void update(int x,int d,int p)
{
int l = tr[p].l, r = tr[p].r;
if(l==r)
{
tr[p].val = {d};
return ;
}
int m = (l+r)/2;
if(x<=m) update(x,d,p<<1);
else update(x,d,p<<1|1);
pushup(p);
}
int search(int x,int y,int d,int p)
{
int l = tr[p].l , r = tr[p].r;
int m = (l+r)/2;
if(tr[p].val.minn > d) return -1;
if(l==r) return l;
if(tr[p<<1].val.minn < d) return search(x,m,d,p<<1);
else return search(m+1,y,d,p<<1|1);
}
vector<PII> qu[N];
int ans[N],pos[N];
void solve()
{
cin>>n>>q;
for(int i=1;i<=n;++i)
{
cin>>a[i];
a[i] = min(a[i],n+1);
}
build(1,n,1);
for(int i=1;i<=q;++i)
{
int l,r;
cin>>l>>r;
qu[r].push_back({l,i});
}
for(int r=1;r<=n;++r)
{
update(a[r]+1,r,1);
for(auto [l,i]:qu[r]) ans[i] = search(1,n,l,1);
}
for(int i=1;i<=q;++i) cout<<ans[i]-1<<'\n';
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T=1;
while(T--)
{
solve();
}
}
笛卡尔树
题意:给定一个 1∼n的排列p,构造一个 1∼n的排列 q,满足对于任意区间 l,r,满足 pl,pl+1,…,pr中的最小值的位置,和ql,ql+1,…,qr的最小值的位置相同。输出满足条件的字典序最小的 q
题解:所有区间的最小值位置一样即两个排列的笛卡尔树一样,由于要字典序最小,所以再p的笛卡尔树上先序遍历赋值构造即可
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 1e6+10;
int a[N],l[N],r[N],ans[N];
int tot,n;
void dfs(int u)
{
ans[u] = ++tot;
if(l[u]) dfs(l[u]);
if(r[u]) dfs(r[u]);
}
void build()
{
int root = 0;
stack<int> stk;
for(int i=1;i<=n;++i)
{
int last = 0;
while(stk.size()&&a[i]<a[stk.top()])
{
last = stk.top();
stk.pop();
}
if(!stk.empty()) r[stk.top()] = i;
else root = i;
l[i] = last;
stk.push(i);
}
dfs(root);
}
void solve()
{
cin>>n;
for(int i=1;i<=n;++i) cin>>a[i];
build();
for(int i=1;i<=n;++i) cout<<ans[i]<<" \n"[i==n];
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T=1;
while(T--)
{
solve();
}
}
st表
RMQ
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
unsigned int A, B, C;
inline unsigned int rng61() {
A ^= A << 16;
A ^= A >> 5;
A ^= A << 1;
unsigned int t = A;
A = B;
B = C;
C ^= t ^ A;
return C;
}
const int N = 1e6+10;
int n,q;
uint a[N],st[22][N];
void init_st()
{
for(int i=1;i<=n;++i) st[0][i] = a[i];
for(int j=1;j<=20;++j)
for(int i=1;i+(1<<(j-1))-1<=n;++i)
{
st[j][i] = max(st[j-1][i] , st[j-1][i+(1<<(j-1))]);
}
}
uint RMQ(int l,int r)
{
int len = __lg(r-l+1);
return max(st[len][l],st[len][r-(1<<len)+1]);
}
void solve()
{
cin>>n>>q>>A>>B>>C;
uint ans = 0;
for (int i = 1; i <= n; i++) {
a[i] = rng61();
}
init_st();
for (int i = 1; i <= q; i++) {
unsigned int l = rng61() % n + 1, r = rng61() % n + 1;
if (l > r) swap(l, r);
int tmp = RMQ(l,r);
ans^=tmp;
}
cout<<ans<<'\n';
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T=1;
while(T--)
{
solve();
}
}
带权并查集
题意:n个数 操作1: 给定线索 2: 回答a[l]-a[r],题目通过2的答案修改t,强制在线
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 2e5+10;
ll w[N];
int f[N];
int find(int x)
{
if(f[x]==x) return x;
int p = f[x];
int q = find(f[x]);
w[x] = w[x] + w[p];
return f[x] = q;
}
void solve()
{
int n,q;
cin>>n>>q;
for(int i=1;i<=n;++i) f[i] = i;
ll t = 0;
for(int i=0;i<q;++i)
{
int op;
cin>>op;
ll l,r,x;
if(op&1)
{
cin>>l>>r>>x;
l = (l+t)%n+1, r = (r+t)%n+1;
int pl = find(l), pr = find(r);
if(pl == pr) continue;
f[pl] = pr;
w[pl] = x + w[r] - w[l];
}
else
{
cin>>l>>r;
l = (l+t)%n+1, r = (r+t)%n+1;
int pl = find(l), pr = find(r);
if(pl != pr) continue;
ll res = w[l] - w[r];
cout<<res<<'\n';
t = abs(res);
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T=1;
while(T--)
{
solve();
}
}
根号分治
经典分治(取模数,普通图)
等差数列加
题意:初始值为0长度为n的数组a 操作1.令a[i%x==y] += d 2.求a[x]
题解: 对于 直接操作不会超过次,对 的数用保存mod i == j的加和
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int B = 500;
ll f[B+1][B];
void solve()
{
int B = 500;
int n,q;
cin>>n>>q;
vector<ll> a(n+1);
while(q--)
{
int op;
cin>>op;
if(op&1)
{
int x,y,d;
cin>>x>>y>>d;
if(x<=B) f[x][y] += d;
else
{
for(int i=y;i<=n;i+=x) a[i] += d;
}
}
else
{
int x;
cin>>x;
ll tmp = 0;
for(int i=1;i<=B;++i) tmp += f[i][x%i];
cout<<a[x] + tmp<<'\n';
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T=1;
while(T--)
{
solve();
}
}
图染色
题意:n个点,m条边的无向图,初始全为白点 操作1.翻转x 2.查询x的邻居有多少黑点
题解:对度数小的点查询直接遍历,对度数大的点在修改时维护出来,给每个点建大点图,每个点至多会有条边
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 2e5+10;
const int B = 500;
bool st[N],big[N];
vector<int> e[N],bige[N];
int ans[N];
void solve()
{
int n,m,q;
cin>>n>>m>>q;
while(m--)
{
int u,v;
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
for(int i=1;i<=n;++i)
{
big[i] = (e[i].size()>=B);
}
for(int i=1;i<=n;++i)
{
for(auto v:e[i]) if(big[v]) bige[i].push_back(v);
}
while(q--)
{
int op,x;
cin>>op>>x;
if(op&1)
{
st[x] = !st[x];
for(auto v:bige[x])
{
if(st[x]) ans[v]++;
else ans[v]--;
}
}
else
{
if(big[x]) cout<<ans[x]<<'\n';
else
{
int tmp = 0;
for(auto v:e[x]) if(st[v]) tmp++;
cout<<tmp<<'\n';
}
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T=1;
while(T--)
{
solve();
}
}
莫队、
莫队是解决容易完成区间添加和删除单个元素,但难以合并的问题,将区间合并的问题转化为元素的增加和减少
小z的袜子
题意:c[i]表示袜子的种类 每个询问求每次求区间[l,r]中选出两个相同类型的袜子概率
题解:将[l,r]按l分块,那么每次对一个块内的所有询问,l的下标移动是的r的下标移动是n的,总体复杂度n
优化:将偶数块的r按从小到大排序,奇数块从大道小排序可以减少r移动的次数
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 50010,Ba = 200;
int c[N],cnt[N];
ll ans[N][2];
vector<array<int,3>> qu;
void solve()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;++i) cin>>c[i];
for(int i=1;i<=m;++i)
{
int l,r;
cin>>l>>r;
if(l == r) {ans[i][0] = 0,ans[i][1] = 1;continue;}
qu.push_back({l,r,i});
ans[i][1] = (ll)(r-l+1)*(r-l)/2;
}
sort(qu.begin(),qu.end(),[&](array<int,3> A,array<int,3> B)
{
if(A[0]/Ba!=B[0]/Ba) return (A[0]/Ba < B[0]/Ba);
if((A[0]/Ba) & 1) return (A[1]>B[1]);
else return (A[1]<B[1]);
});
ll tmp = 0;
auto add = [&](int x)->void
{
tmp += cnt[c[x]]++;
};
auto del = [&](int x)->void
{
tmp -= --cnt[c[x]];
};
int l = 1, r = 0;
for(auto q:qu)
{
int x = q[0], y = q[1];
int id = q[2];
while(r < y) r++, add(r);
while(l > x) l--, add(l);
while(r > y) del(r), r--;
while(l < x) del(l), l++;
int G = __gcd(tmp,ans[id][1]);
ans[id][0] = tmp/G;
ans[id][1] = ans[id][1]/G;
}
for(int i=1;i<=m;++i)
{
cout<<ans[i][0]<<'/'<<ans[i][1]<<'\n';
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T = 1;
while(T--)
{
solve();
}
}
重复的数
题意:给定n个数 有m次询问 每次询问[l,r]里有多少个数的出现次数恰好为k
题解:莫队,维护区间每个数出现的次数以及区间内出现该次数的数字个数
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 1e5+10,Ba = 500;
int a[N],cnt[N],fre[N];
int ans[N];
vector<array<int,4>> qu;
void solve()
{
int n,m;
cin>>n;
for(int i=1;i<=n;++i) cin>>a[i];
cin>>m;
for(int i=1;i<=m;++i)
{
int l,r,k;
cin>>l>>r>>k;
qu.push_back({l,r,k,i});
}
sort(qu.begin(),qu.end(),[&](array<int,4> A,array<int,4> B)
{
if(A[0]/Ba!=B[0]/Ba) return (A[0]/Ba < B[0]/Ba);
if((A[0]/Ba) & 1) return (A[1]>B[1]);
else return (A[1]<B[1]);
});
auto add = [&](int x)->void
{
fre[cnt[a[x]]]--;
fre[++cnt[a[x]]]++;
};
auto del = [&](int x)->void
{
fre[cnt[a[x]]]--;
fre[--cnt[a[x]]]++;
};
int l = 1, r = 0;
for(auto q:qu)
{
int x = q[0], y = q[1], k = q[2];
int id = q[3];
while(r < y) r++, add(r);
while(l > x) l--, add(l);
while(r > y) del(r), r--;
while(l < x) del(l), l++;
ans[id] = fre[k];
}
for(int i=1;i<=m;++i)
{
cout<<ans[i]<<'\n';
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T = 1;
while(T--)
{
solve();
}
}
树上倍增
路径最小值
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 2e5+10;
vector<PII> e[N];
const int M = 20;
int par[20][N],val[20][N],dep[N];
int n;
void dfs(int u,int f)
{
for(auto [v,w]:e[u])
{
if(v==f) continue;
dep[v] = dep[u] + 1;
par[0][v] = u;
val[0][v] = w;
dfs(v,u);
}
}
void init_st()
{
for(int j=1;j<M;++j)
for(int i=1;i<=n;++i)
{
val[j][i] = min(val[j-1][i],val[j-1][par[j-1][i]]);
par[j][i] = par[j-1][par[j-1][i]];
}
}
int qu_tree(int u,int v)
{
int ans = 1<<30;
if(dep[u]<dep[v]) swap(u,v);
int d =dep[u] - dep[v];
for(int i=0;i<=20&&d;i++,d>>=1)
{
if(d&1) ans = min(val[i][u],ans), u = par[i][u];
}
if(u==v) return ans;
for(int i=19;i>=0;--i)
{
if(par[i][u]!=par[i][v])
{
ans = min({ans,val[i][u],val[i][v]});
u = par[i][u], v = par[i][v];
}
}
ans = min({ans,val[0][u],val[0][v]});
return ans;
}
void solve()
{
int q;
cin>>n>>q;
memset(val,0x3f,sizeof val);
for(int i=1;i<n;++i)
{
int u,v,w;
cin>>u>>v>>w;
e[u].push_back({v,w});
e[v].push_back({u,w});
}
dfs(1,0);
init_st();
for(int i=0;i<q;++i)
{
int u,v;
cin>>u>>v;
cout<<qu_tree(u,v)<<'\n';
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T = 1;
while(T--)
{
solve();
}
}
dfs序
题意:n个点,每个点w[i],操作1. 修改a[x] = y 2.查询x的子树和以及到根路径和
题解:按照dfs序每个点有l[i]和r[i],将子树和转化为BIT1的[li,ri]区间和,每次修改将BIT2的[li,ri]修改把路径和转化为单点求和
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 2e5+10;
vector<int> e[N];
template <class T>
struct BIT
{
T c[N];
int sz;
void init(int s)
{
sz = s;
for(int i=1;i<=sz;++i) c[i] = 0;
}
T lowbit(int x)
{
return x&-x;
}
T sum(int x)
{
assert(x <= sz);
T res=0;
while(x) res+=c[x],x-=lowbit(x);
return res;
}
void update(int x,int y)
{
assert(x != 0);
while(x<=sz) c[x]+=y,x+=lowbit(x);
}
};
BIT <ll> c1, c2;
int a[N],l[N],r[N];
int tot;
void dfs(int u,int f)
{
l[u] = ++tot;
for(auto v:e[u])
{
if(v == f) continue;
dfs(v,u);
}
r[u] = tot;
}
void solve()
{
int n,q;
cin>>n>>q;
c1.init(n);c2.init(n);
for(int i=0;i<n-1;++i)
{
int u,v;
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
dfs(1,0);
for(int i=1;i<=n;++i)
{
cin>>a[i];
c1.update(l[i],a[i]);
c2.update(l[i],a[i]);
c2.update(r[i]+1,-a[i]);
}
for(int i=1;i<=q;++i)
{
int op;
cin>>op;
if(op&1)
{
int x, y;
cin>>x>>y;
int d = y - a[x];
a[x] = y;
c1.update(l[x],d);
c2.update(l[x],d);
c2.update(r[x]+1,-d);
}
else
{
int x;
cin>>x;
cout<<c1.sum(r[x]) - c1.sum(l[x]-1)<<' '<<c2.sum(l[x])<<'\n';
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T = 1;
while(T--)
{
solve();
}
}
dfs序2
题意:n个点 w[i] 1为根 操作1.w[x] = y 2.求x的子树和 3.修改根为x
题解:最主要是换根问题,考虑若查询的x==root则ans = sum[n]否则若root在x的子树里(即l[root]>l[x]&&r[root]<=r[x])要找到root在x的哪个子节点y上,ans = sum[n] - sum[r[y]] - sum[l[y]-1]
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 2e5+10;
vector<int> e[N];
vector<PII> son[N];
template <class T>
struct BIT
{
T c[N];
int sz;
void init(int s)
{
sz = s;
for(int i=1;i<=sz;++i) c[i] = 0;
}
T lowbit(int x)
{
return x&-x;
}
T sum(int x)
{
assert(x <= sz);
T res=0;
while(x) res+=c[x],x-=lowbit(x);
return res;
}
void update(int x,int y)
{
assert(x != 0);
while(x<=sz) c[x]+=y,x+=lowbit(x);
}
};
BIT <ll> c1;
int a[N],l[N],r[N];
int tot;
void dfs(int u,int f)
{
l[u] = ++tot;
for(auto v:e[u])
{
if(v == f) continue;
dfs(v,u);
son[u].push_back({l[v],r[v]});
}
r[u] = tot;
}
void solve()
{
int n,q;
cin>>n>>q;
c1.init(n);
for(int i=0;i<n-1;++i)
{
int u,v;
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
dfs(1,0);
for(int i=1;i<=n;++i)
{
cin>>a[i];
c1.update(l[i],a[i]);
}
int root = 1;
for(int i=1;i<=q;++i)
{
int op;
cin>>op;
if(op == 1)
{
int x, y;
cin>>x>>y;
int d = y - a[x];
a[x] = y;
c1.update(l[x],d);
}
else if(op == 2)
{
int x;
cin>>x;
if(x == root) cout<<c1.sum(n)<<'\n';
else if(l[root]>l[x]&&r[root]<=r[x])
{
auto seg = *prev(upper_bound(son[x].begin(),son[x].end(),
PII{l[root],r[root]}));
cout<<c1.sum(n) - (c1.sum(seg.y) - c1.sum(seg.x - 1))<<'\n';
}
else
{
cout<<c1.sum(r[x]) - c1.sum(l[x]-1)<<'\n';
}
}
else
{
int x;
cin>>x;
root = x;
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T = 1;
while(T--)
{
solve();
}
}
启发式合并
梦幻布丁
注意e[x].clear()不释放内存,可以用vector().swap(e[x])释放,swap时间复杂度是O(1)的
#include<bits/stdc++.h>
using namespace std;
const int N = 100010, M = 1000010;
int n, m;
vector<int> e[M];
int color[N];
int ans;
void add(int u, int v)
{
e[u].push_back(v);
}
void merge(int x, int y)
{
if (x == y) return;
if (e[x].size() > e[y].size()) e[x].swap(e[y]);
int col = color[e[y][0]];
for (auto v:e[x])
{
ans -= (color[v - 1] != color[v]) + (color[v + 1] != color[v]);
color[v] = col;
ans += (color[v - 1] != color[v]) + (color[v + 1] != color[v]);
}
for (auto v:e[x])
{
e[y].push_back(v);
}
vector<int>().swap(e[x]);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m;
for (int i = 1; i <= n; i ++ )
{
cin>>color[i];
if (color[i] != color[i - 1]) ans ++;
add(color[i], i);
}
ans++;
while (m -- )
{
int op;
cin>>op;
if (op == 2) cout<<ans-1<<'\n';
else
{
int x, y;
cin>>x>>y;
merge(x, y);
}
}
return 0;
}
路径最小值
题解:按边从大到小排序,每次将两个集合合并,此时的边就是询问点分别在两个集合中的路径最小值
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 2e5+10;
array<int,3> E[N];
int ans[N],f[N];
map<int,int> qu[N];
set<int> vec[N];
int find(int x)
{
if(f[x]==x) return x;
return f[x] = find(f[x]);
}
void solve()
{
int n,q;
cin>>n>>q;
for(int i=1;i<=n;++i) f[i] = i, vec[i].insert(i);
for(int i=0;i<n-1;++i)
{
int u,v,w;
cin>>u>>v>>w;
E[i][0] = w,E[i][1] = u,E[i][2] = v;
}
for(int i=0;i<q;++i)
{
int u,v;
cin>>u>>v;
qu[u][i] = v;
qu[v][i] = u;
}
sort(E,E+n-1);
reverse(E,E+n-1);
for(int i=0;i<n-1;++i)
{
int u = E[i][1], v = E[i][2], w = E[i][0];
u = find(u), v = find(v);
if(vec[u].size() > vec[v].size()) swap(u,v);
for(auto [id,t]:qu[u])
{
if(vec[v].count(t)) ans[id] = w, qu[v].erase(id);
else qu[v][id] = t;
}
qu[u].clear();
for(auto t:vec[u]) vec[v].insert(t);
vec[u].clear();
f[u] = v;
}
for(int i=0;i<q;++i) cout<<ans[i]<<"\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T = 1;
while(T--)
{
solve();
}
}
优化
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 2e5+10;
array<int,3> E[N];
int ans[N],f[N],belong[N];
vector<PII> qu[N];
vector<int> vec[N];
int find(int x)
{
if(f[x]==x) return x;
return f[x] = find(f[x]);
}
void solve()
{
int n,q;
cin>>n>>q;
for(int i=1;i<=n;++i)
{
f[i] = i, belong[i] = i;
vec[i].push_back(i);
}
for(int i=0;i<n-1;++i)
{
int u,v,w;
cin>>u>>v>>w;
E[i][0] = w,E[i][1] = u,E[i][2] = v;
}
for(int i=0;i<q;++i)
{
int u,v;
cin>>u>>v;
qu[u].push_back({i,v});
qu[v].push_back({i,u});
}
sort(E,E+n-1);
reverse(E,E+n-1);
for(int i=0;i<n-1;++i)
{
int u = E[i][1], v = E[i][2], w = E[i][0];
u = find(u), v = find(v);
if(vec[u].size() > vec[v].size()) swap(u,v);
for(auto [id,t]:qu[u])
{
if(ans[id]) continue;
if(belong[t] == v) ans[id] = w;
else qu[v].push_back({id,t});
}
qu[u].clear();
for(auto t:vec[u])
{
belong[t] = v;vec[v].push_back(t);
}
vec[u].clear();
f[u] = v;
}
for(int i=0;i<q;++i) cout<<ans[i]<<"\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T = 1;
while(T--)
{
solve();
}
}
启发式分治
好序列
若能使得T(n) = T(x) + T(n-x) + O(min(x,n-x)),则复杂度为nlogn
题意:一个长为n的序列。定义一个序列是好的, 当且仅当他的每一个子区间满足,至少存在一个元素x仅出现了一次。求是否为好序列
若有一个数a[i]在[1,n]中只出现了一次,则所有包含a[i]的区间都是合法的,只需考虑[1,i-1]和[i+1,n]
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 2e5+10;
int a[N],pre[N],nxt[N];
bool deal(int l,int r)
{
if(l > r) return true;
for(int i = l,j = r;i <= j; i++, j--)
{
if(pre[i]<l && nxt[i]>r) return deal(l,i-1)&&deal(i+1,r);
if(pre[j]<l && nxt[j]>r) return deal(l,j-1)&&deal(j+1,r);
}
return false;
};
void solve()
{
int n;
cin>>n;
map<int,int> pos;
for(int i=1;i<=n;++i)
{
cin>>a[i];
if(pos.find(a[i])!=pos.end()) pre[i] = pos[a[i]];
else pre[i] = 0;
pos[a[i]] = i;
}
pos.clear();
for(int i=n;i>=1;--i)
{
if(pos.find(a[i])!=pos.end()) nxt[i] = pos[a[i]];
else nxt[i] = n+1;
pos[a[i]] = i;
}
cout<<(deal(1,n)?("non-boring\n"):("boring\n"));
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin>>T;
while(T--)
{
solve();
}
}
DSU on tree
Lomsat gelral
题意:n个节点的树,每个点有一个颜色,求每个点子树颜色的众数和
题解:保留重儿子舍去轻儿子,做启发式合并
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 2e5+10;
vector<int> e[N];
int sz[N],son[N],l[N],r[N],id[N];
int c[N],cnt[N];
ll tot,maxsum,maxcnt;
ll ans[N];
void dfs_init(int u,int f)
{
l[u] = ++tot;
id[tot] = u;
sz[u]++;
for(auto v:e[u])
{
if(v==f) continue;
dfs_init(v,u);
if(sz[v]>sz[son[u]]) son[u] = v;
sz[u] += sz[v];
}
r[u] = tot;
}
void dsu_on_tree(int u,int f,bool keep)
{
for(auto v:e[u])
{
if(v==f||v==son[u]) continue;
dsu_on_tree(v,u,0);
}
if(son[u]) dsu_on_tree(son[u],u,1);
auto add = [&](int x)
{
x = c[x];
cnt[x]++;
if(cnt[x] > maxcnt) maxcnt = cnt[x], maxsum = x;
else if(cnt[x] == maxcnt) maxsum += x;
};
auto del = [&](int x)
{
x = c[x];
cnt[x]--;
};
for(auto v:e[u])
{
if(v==f||v==son[u]) continue;
for(int i = l[v];i <= r[v]; ++i) add(id[i]);
}
add(u);
ans[u] = maxsum;
if(!keep)
{
maxcnt = 0, maxsum = 0;
for(int i = l[u];i <= r[u]; ++i) del(id[i]);
}
}
void solve()
{
int n;
cin>>n;
for(int i=1;i<=n;++i) cin>>c[i];
for(int i=1;i<=n-1;++i)
{
int u,v;
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
dfs_init(1,0);
dsu_on_tree(1,0,0);
for(int i=1;i<=n;++i) cout<<ans[i]<<" ";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T = 1;
while(T--)
{
solve();
}
}
树链剖分
类似启发式合并的思想,从一个节点出发,经过的轻链个数至多logn次
LCA
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 2e5+10;
vector<int> e[N];
int tot,l[N],r[N],id[N];
int top[N],sz[N],son[N],fa[N],dep[N];
void dfs1(int u,int f)
{
sz[u]++;
fa[u] = f;
for(auto v:e[u])
{
if(v==f) continue;
dep[v] = dep[u] + 1;
dfs1(v,u);
if(sz[v]>sz[son[u]]) son[u] = v;
sz[u] += sz[v];
}
}
void dfs2(int u,int f,int t)
{
l[u] = ++tot;
id[tot] = u;
top[u] = t;
if(son[u])
{
dfs2(son[u],u,t);
}
for(auto v:e[u])
{
if(v==f||v==son[u]) continue;
dfs2(v,u,v);
}
r[u] = tot;
}
int LCA(int u,int v)
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) v = fa[top[v]];
else u = fa[top[u]];
}
if(dep[u]<dep[v]) return u;
else return v;
}
void solve()
{
int n,q;
cin>>n;
for(int i=0;i<n-1;++i)
{
int u,v;
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
dfs1(1,0);
dfs2(1,0,1);
cin>>q;
for(int i=0;i<q;++i)
{
int u,v;
cin>>u>>v;
cout<<LCA(u,v)<<'\n';
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T = 1;
while(T--)
{
solve();
}
}
ZJOI2008, 树的统计
树链剖分板子, 注意线段树上的标号是dfs序
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 2e5+10;
vector<int> e[N];
int tot,l[N],r[N],id[N];
int top[N],sz[N],son[N],fa[N],dep[N];
void dfs1(int u,int f)
{
sz[u]++;
fa[u] = f;
for(auto v:e[u])
{
if(v==f) continue;
dep[v] = dep[u] + 1;
dfs1(v,u);
if(sz[v]>sz[son[u]]) son[u] = v;
sz[u] += sz[v];
}
}
void dfs2(int u,int f,int t)
{
l[u] = ++tot;
id[tot] = u;
top[u] = t;
if(son[u])
{
dfs2(son[u],u,t);
}
for(auto v:e[u])
{
if(v==f||v==son[u]) continue;
dfs2(v,u,v);
}
r[u] = tot;
}
int a[N];
struct info
{
ll maxn,sum;
};
info operator + (const info& l,const info& r)
{
return (info){max(l.maxn,r.maxn),l.sum+r.sum};
}
struct node
{
int l,r;
info val;
}tr[N<<2];
void pushup(int p)
{
tr[p].val = tr[p<<1].val + tr[p<<1|1].val;
}
void build(int l,int r,int p)
{
tr[p].l = l,tr[p].r = r;
if(l==r)
{
tr[p].val = (info){a[id[l]], a[id[l]]};
return ;
}
int m = (l+r)/2;
build(l,m,p<<1);
build(m+1,r,p<<1|1);
pushup(p);
}
void update(int x,int d,int p)
{
int l = tr[p].l, r = tr[p].r;
if(l==r)
{
tr[p].val = (info){d, d};
return ;
}
int m = (l+r)/2;
if(x<=m) update(x,d,p<<1);
else update(x,d,p<<1|1);
pushup(p);
}
info query(int x,int y,int p)
{
int l = tr[p].l,r = tr[p].r;
if(x==l&&r==y) return tr[p].val;
int m = (l+r)/2;
if(y<=m) return query(x,y,p<<1);
else if(x>m) return query(x,y,p<<1|1);
else return query(x,m,p<<1)+query(m+1,y,p<<1|1);
}
info query(int u,int v)
{
info ans{(ll)-1e9,0};
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])
{
ans = ans + query(l[top[v]],l[v],1);
v = fa[top[v]];
}
else
{
ans = ans + query(l[top[u]],l[u],1);
u = fa[top[u]];
}
}
if(dep[u]<dep[v]) return ans + query(l[u],l[v],1);
else return ans + query(l[v],l[u],1);
}
void solve()
{
int n,q;
cin>>n;
for(int i=0;i<n-1;++i)
{
int u,v;
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
for(int i=1;i<=n;++i) cin>>a[i];
dfs1(1,0);
dfs2(1,0,1);
build(1,n,1);
cin>>q;
for(int i=0;i<q;++i)
{
int u,v;
char op[10];
cin>>op>>u>>v;
if(op[0]=='C')
{
update(l[u],v,1);
}
else if(op[1]=='M')
{
cout<<query(u,v).maxn<<'\n';
}
else cout<<query(u,v).sum<<'\n';
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T = 1;
while(T--)
{
solve();
}
}
SDOI 染色
树链剖分之区间更新,注意区间和并时的顺序
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
const int N = 2e5+10;
vector<int> e[N];
int tot,l[N],r[N],id[N];
int top[N],sz[N],son[N],fa[N],dep[N];
void dfs1(int u,int f)
{
sz[u]++;
fa[u] = f;
for(auto v:e[u])
{
if(v==f) continue;
dep[v] = dep[u] + 1;
dfs1(v,u);
if(sz[v]>sz[son[u]]) son[u] = v;
sz[u] += sz[v];
}
}
void dfs2(int u,int f,int t)
{
l[u] = ++tot;
id[tot] = u;
top[u] = t;
if(son[u])
{
dfs2(son[u],u,t);
}
for(auto v:e[u])
{
if(v==f||v==son[u]) continue;
dfs2(v,u,v);
}
r[u] = tot;
}
int a[N];
struct info
{
int l_col,r_col,seg;
info() {}
info(int a) :l_col(a),r_col(a),seg(0) {}
info(int a,int b,int c) :l_col(a),r_col(b),seg(c) {}
};
struct tag
{
int col;
tag() {}
tag(int a):col(a) {}
};
info operator + (const info& l,const info& r)
{
return info(l.l_col,r.r_col,l.seg+r.seg + (l.r_col != r.l_col));
}
info operator + (const info &v,const tag& t)
{
return info(t.col,t.col,0);
}
tag operator + (const tag &t1,const tag&t2)
{
return t2;
}
struct node
{
int l,r;
info val;
tag t;
}tr[N<<2];
void settag(int p,tag t)
{
tr[p].val = tr[p].val + t;
tr[p].t = tr[p].t + t;
}
void pushup(int p)
{
tr[p].val = tr[p<<1].val + tr[p<<1|1].val;
}
void pushdown(int p)
{
if(tr[p].t.col)
{
settag(p<<1,tr[p].t);
settag(p<<1|1,tr[p].t);
tr[p].t.col = 0;
}
}
void build(int l,int r,int p)
{
tr[p].l = l,tr[p].r = r;
if(l==r)
{
tr[p].val = info(a[id[l]]);
return ;
}
int m = (l+r)/2;
build(l,m,p<<1);
build(m+1,r,p<<1|1);
pushup(p);
}
void update(int x,int y,tag C,int p)
{
int l = tr[p].l, r = tr[p].r;
if(l==x&&r==y)
{
settag(p,C);
return ;
}
pushdown(p);
int m = (l+r)/2;
if(y<=m) update(x,y,C,p<<1);
else if(x>m) update(x,y,C,p<<1|1);
else
{
update(x,m,C,p<<1);
update(m+1,y,C,p<<1|1);
}
pushup(p);
}
info query(int x,int y,int p)
{
int l = tr[p].l,r = tr[p].r;
if(x==l&&r==y) return tr[p].val;
pushdown(p);
info ans;
int m = (l+r)/2;
if(y<=m) return query(x,y,p<<1);
else if(x>m) return query(x,y,p<<1|1);
else return query(x,m,p<<1)+query(m+1,y,p<<1|1);
}
void update(int u,int v,tag C)
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
update(l[top[u]],l[u],C,1);
u = fa[top[u]];
}
if(dep[u]<dep[v]) swap(u,v);
update(l[v],l[u],C,1);
}
int query(int u,int v)
{
info ansu(0,0,-1),ansv(0,0,-1);
if(l[u]>l[v]) swap(u,v);
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])
{
ansv = query(l[top[v]],l[v],1) + ansv;
v = fa[top[v]];
}
else
{
ansu = query(l[top[u]],l[u],1) + ansu;
u = fa[top[u]];
}
}
if(dep[u] < dep[v]) ansv = query(l[u],l[v],1) + ansv;
else ansu = query(l[v],l[u],1) + ansu;
return ansu.seg + ansv.seg + (ansu.l_col != ansv.l_col) + 1;
}
void solve()
{
int n,q;
cin>>n>>q;
for(int i=1;i<=n;++i) cin>>a[i];
for(int i=0;i<n-1;++i)
{
int u,v;
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
dfs1(1,0);
dfs2(1,0,1);
build(1,n,1);
for(int i=0;i<q;++i)
{
char op;
cin>>op;
if(op == 'C')
{
int a,b,c;
cin>>a>>b>>c;
update(a,b,(tag){c});
}
else
{
int a,b;
cin>>a>>b;
cout<<query(a,b)<<'\n';
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T = 1;
while(T--)
{
solve();
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下