题解
٩(๑>◡<๑)۶人生第一道动态点分治٩(๑>◡<๑)۶
一开始我点分治都不怎么会,更别说动态点分治了
然后开始肝题解和std,肝了我两天,终于搞懂了
然后写了一上午+下午,调了一晚上,终于A掉了
如果不知道动态点分治,请看这里
其实这道题思路并不难想
点分树+线段树
只是修改边的时候会比较麻烦
考虑一条边改变权值会对哪些点产生影响,其实就是对dep值较大的端点的子树造成影响
但是在不同的点分中心下,这两个端点的dep值大小关系可能是不同的
所以边往上爬,边比较大小,修改线段树
我的代码中用的是dis值来比较的大小
这导致了一个我调了3个小时的错误:查询时会用到一个点到某个点分中心的dis,但是这个dis是会改变的,不能通过预处理保存下来,所以每次更新都需要边往上爬,边比较大小,边查询当前dis值,边修改线段树
这样就A了
代码:(其实还有一个错误,但是这个错误不影响程序的正确性,因为我们只需要保证该点自身不被查询到即可,所以在去除子树贡献是就不用那么严,可以少开一个fro数组)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
#define N 100005
#define LOG 18
#define LL long long
#define lc a[i].lch
#define rc a[i].rch
const LL INF=1ll<<60;
int fir[N],to[2*N],nxt[2*N],cnt;LL cd[2*N];
int siz[LOG][N],dfn[LOG][N],dc,dfa[N],dep[N];LL dis[LOG][N];
int tmpsiz[N],nrt,all;bool vis[N];
struct ansnode{
LL mx;int pos;
ansnode(){}
ansnode(LL a,int b){mx=a;pos=b;}
bool operator < (const ansnode &t)const{return mx<t.mx||(mx==t.mx&&pos>t.pos);}
}ans,tans;
struct node{int l,r,lch,rch;LL la;ansnode x;}a[N*LOG*3];
int T[N],tot;
LL val[N];//
map<pair<int,int>,LL> mp;
inline LL gi()
{
char c;LL num=0;
while((c=getchar())<'0'||c>'9');
while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
return num;
}
void adde(int a,int b,LL c)
{
to[++cnt]=b;nxt[cnt]=fir[a];fir[a]=cnt;cd[cnt]=c;
to[++cnt]=a;nxt[cnt]=fir[b];fir[b]=cnt;cd[cnt]=c;
}
void findrt(int u,int ff)
{
int mx=0;tmpsiz[u]=1;
for(int v,p=fir[u];p;p=nxt[p]){
if((v=to[p])!=ff&&!vis[v]){
findrt(v,u);
tmpsiz[u]+=tmpsiz[v];
mx=max(mx,tmpsiz[v]);
}
}
mx=max(mx,all-tmpsiz[u]);
if(2*mx<=all)nrt=u;//mdzz wssb
}
int getrt(int u,int al)
{
nrt=-1000000000;all=al;//-1e9:prevent the explosion of findrt
findrt(u,0);return nrt;
}
int tmpid[N];LL tmpval[N];
void pushdown(int i)
{
if(a[i].la!=0&&a[i].l<a[i].r){
a[lc].x.mx+=a[i].la;a[lc].la+=a[i].la;
a[rc].x.mx+=a[i].la;a[rc].la+=a[i].la;
a[i].la=0;
}
}
void build(int &i,int l,int r)
{
if(!i)i=++tot,a[i].l=l,a[i].r=r;
if(l==r){a[i].x.mx=tmpval[l],a[i].x.pos=tmpid[l];return;}
int mid=(l+r)>>1;
build(lc,l,mid);build(rc,mid+1,r);
a[i].x=max(a[lc].x,a[rc].x);
}
void insert(int i,int l,int r,LL k)
{
if(a[i].l>r||l>a[i].r)return;
pushdown(i);
if(l<=a[i].l&&a[i].r<=r){
a[i].x.mx+=k;a[i].la+=k;
return;
}
insert(lc,l,r,k);insert(rc,l,r,k);
a[i].x=max(a[lc].x,a[rc].x);
}
ansnode query(int i,int l,int r)
{
if(a[i].l>r||a[i].r<l)return ansnode(-INF,1<<30);
pushdown(i);
if(l<=a[i].l&&a[i].r<=r)return a[i].x;
return max(query(lc,l,r),query(rc,l,r));
}
void pre(int u,int ff,int d)
{
dfn[d][u]=++dc;siz[d][u]=1;
tmpid[dc]=u;tmpval[dc]=val[u]-dis[d][u];
for(int v,p=fir[u];p;p=nxt[p]){
if(!vis[v=to[p]]&&v!=ff){
dis[d][v]=dis[d][u]+cd[p];
pre(v,u,d);
siz[d][u]+=siz[d][v];
}
}
}
void DFZ(int u,int d)
{
vis[u]=1;dep[u]=d;
dc=0;dis[d][u]=0;pre(u,0,d);
if(siz[d][u]>1)build(T[u],2,siz[d][u]);
for(int v,p=fir[u];p;p=nxt[p]){
if(!vis[v=to[p]]){
dfa[v=getrt(v,siz[d][v])]=u;
DFZ(v,d+1);
}
}
}
int main()
{
freopen("buy.in","r",stdin);
freopen("buy.out","w",stdout);
int n,Q,i,op,u,v,t;LL w,tmp;
n=gi();Q=gi();
for(i=1;i<=n;i++)val[i]=gi();
for(i=1;i<n;i++){
u=gi();v=gi();w=gi();
adde(u,v,w);
if(u>v)swap(u,v);
mp[make_pair(u,v)]=w;
}
DFZ(getrt(1,n),1);
int now=1;
for(i=1;i<=Q;i++){
op=gi();
if(op==1){
u=gi();w=gi();
tmp=w-val[u];val[u]=w;
for(t=dfa[u];t;t=dfa[t])
insert(T[t],dfn[dep[t]][u],dfn[dep[t]][u],tmp);
}
else{
u=gi();v=gi();w=gi();
if(u>v)swap(u,v);
tmp=w-mp[make_pair(u,v)];
mp[make_pair(u,v)]=w;
for(t=(dep[u]>dep[v]?v:u);t;t=dfa[t]){
if(dis[dep[t]][u]<dis[dep[t]][v])swap(u,v);
insert(T[t],dfn[dep[t]][u],dfn[dep[t]][u]+siz[dep[t]][u]-1,-tmp);
}
}
ans=ansnode(-INF,1<<30);
if(T[now])ans=query(T[now],2,siz[dep[now]][now]);
//if(ans.pos!=(1<<30))printf("%d: %lld %d\n",i,ans.mx,ans.pos);
for(t=dfa[now];t;t=dfa[t]){
//LL del=dis[dep[t]][now];//wrong !!!!
LL del=-(query(T[t],dfn[dep[t]][now],dfn[dep[t]][now]).mx-val[now]);
//dis will change !!!!
tans=max(ansnode(val[t],t),max(query(T[t],2,dfn[dep[t]][now]-1),query(T[t],dfn[dep[t]][now]+siz[dep[t]][now],siz[dep[t]][t])));
tans.mx-=del;ans=max(ans,tans);//
//if(ans.pos!=(1<<30))printf("%d: %lld %d\n",i,ans.mx,ans.pos);
}
//printf("%d:### %lld %d\n",i,ans.mx,ans.pos);
//printf("%d: ----------------------------\n",i);
printf("%d\n",ans.pos);
now=ans.pos;
}
}