AT_joisc2018_a
思路
看到这种区间覆盖可以优先考虑 ODT 了,因为每次它都覆盖的是一条路径那么考虑每次用 ODT 来修改,因为 ODT 需要时一个连续的区间所以直接套一个重链剖分即可,然后我们将询问离线,然后对于每一次询问按照通过树链剖分去跳链,然后将其加入树状数组中然后再将查询答案累积到答案中即可。
注意,因为树链剖分的每一个小区间是从前往后遍历的,而树剖又是整体从下往上跳的,故去要将其中一个反着遍历,时间复杂度大概是 \(O(n\log(n)^3)\),成功成为目前最劣解。
代码
#include <bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#include <ext/rope>
using namespace __gnu_pbds;
using namespace std;
#define pb push_back
#define rep(i,x,y) for(register int i=x;i<=y;i++)
#define rep1(i,x,y) for(register int i=x;i>=y;--i)
#define in(x) scanf("%lld",&x)
#define int long long
#define fire signed
#define il inline
il void print(int x) {
if(x<0) putchar('-'),x=-x;
if(x>=10) print(x/10);
putchar(x%10+'0');
}
int T=1;
int n;
struct node{
int l,r;
mutable int val;
friend bool operator<(const node&a,const node&b) {
return a.l<b.l;
}
};
const int N=1e5+10;
vector<int>v[N];
set<node>s;
auto split(int pos) {//ODT
auto it=s.lower_bound({pos,0,0});
if(it!=s.end()&&it->l==pos) return it;
it--;
if(it->r<pos) return s.end();
int l=it->l,r=it->r,v=it->val;
s.erase(it);
s.insert({l,pos-1,v});
return s.insert({pos,r,v}).first;
}
void add(int l,int r,int c) {
auto itr=split(r+1),itl=split(l);
s.erase(itl,itr);
s.insert({l,r,c});
}
int a[N],b[N];
int ans[N];
int dfn[N],son[N],siz[N],f[N],dep[N],top[N];
void dfs(int x,int fa) {
f[x]=fa;
dep[x]=dep[fa]+1;
siz[x]=1;
for(auto to:v[x]) {
if(to==fa) continue;
dfs(to,x);
siz[x]+=siz[to];
if(siz[to]>siz[son[x]]) son[x]=to;
}
}
int idx,mp[N];
void dfs1(int x,int head) {
top[x]=head;
dfn[x]=++idx;
mp[idx]=x;
if(!son[x]) return ;
dfs1(son[x],head);
for(auto to:v[x]) if(!dfn[to]) dfs1(to,to);
}
int res[N];
int lowbit(int x) {
return x&-x;
}
int tr[N];
void add(int x,int k) {
for(;x<=n;x+=lowbit(x)) tr[x]+=k;
}
int Ans(int x) {
int res=0;
for(;x;x-=lowbit(x)) res+=tr[x];
return res;
}
void modify(int x,int y,int &res) {
auto itr=split(y+1),itl=split(x);
itr--;
itl--;
auto it=itr;
for(;itl!=itr;itr--) {
int cnt=itr->r-itr->l+1;
res+=cnt*Ans(itr->val-1);
add(itr->val,cnt);
}
}
void modify1(int x,int y) {
auto itr=split(y+1),itl=split(x);
itr--;
itl--;
auto it=itr;
for(;itl!=itr;itr--) {
int cnt=itr->r-itr->l+1;
add(itr->val,-cnt);
}
}
int Ans(int x,int y) {
int res=0;
int xx=x,yy=y;
while(top[x]!=top[y]) {//树链剖分
if(dep[top[x]]<dep[top[y]]) swap(x,y);
modify(dfn[top[x]],dfn[x],res);
x=f[top[x]];
}
if(dfn[x]>dfn[y]) swap(x,y);
modify(dfn[x],dfn[y],res);
x=xx,y=yy;
while(top[x]!=top[y]) {//清空
if(dep[top[x]]<dep[top[y]]) swap(x,y);
modify1(dfn[top[x]],dfn[x]);
x=f[top[x]];
}
if(dfn[x]>dfn[y]) swap(x,y);
modify1(dfn[x],dfn[y]);
return res;
}
void gai(int x,int y,int k) {
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]]) swap(x,y);
add(dfn[top[x]],dfn[x],k);
x=f[top[x]];
}
if(dfn[x]>dfn[y]) swap(x,y);
add(dfn[x],dfn[y],k);
}
int tt[N];
void solve() {
in(n);
rep(i,1,n) in(a[i]),b[i]=a[i];
sort(b+1,b+1+n);
int m=unique(b+1,b+1+n)-b-1;
rep(i,1,n) a[i]=lower_bound(b+1,b+1+m,a[i])-b;//离散化
rep(i,1,n-1) {
int x,y;
in(x),in(y);
v[x].pb(y);
v[y].pb(x);
ans[i]=x;
tt[i]=y;
}
dfs(1,0);
dfs1(1,1);
rep(i,1,n) s.insert({i,i,a[mp[i]]});
rep(i,1,n-1) res[i]=Ans(1,ans[i]),gai(1,ans[i],a[tt[i]]);
rep(i,1,n-1) printf("%lld\n",res[i]);
}
fire main() {
while(T--) {
solve();
}
return false;
}

浙公网安备 33010602011771号