题意:也是树链剖分的裸题,支持三种操作:1.修改一条边的权值;2.将点u,v路径上的边都取相反数;3.查询u,v路径上边的最大值。
老方法,用边的后继点表示边。这样的做法需要注意在查询和修改时,当两点回到一条链上之后,需要操作的区间不再是id[u]到id[v],而是id[son[u]]到id[v]。
线段树中需要同时维护区间最小值和最大值,二者取相反数后会变成对方。
#include#include #include #include using namespace std;typedef long long LL;const int maxn =1e4+5;const int INF = 0x3f3f3f3f;struct Edge{ int to,next;}E[2*maxn];int n,head[maxn],tot;int idx,size[maxn],fa[maxn],son[maxn],dep[maxn],top[maxn],id[maxn];int edge[maxn][3];void init(){ idx=tot=0; memset(head,-1,sizeof(head)); dep[1]=0,fa[1]=1,size[0]=0; memset(son,0,sizeof(son));}void AddEdge(int u,int v){ E[tot] = (Edge){v,head[u]}; head[u]=tot++;}void dfs1(int u){ size[u]=1; for(int i=head[u];~i;i=E[i].next){ int v=E[i].to; if(v!=fa[u]){ fa[v]=u; dep[v]=dep[u]+1; dfs1(v); size[u]+=size[v]; if(size[son[u]] >1; build(Lson); build(Rson); pushup(rt);}void update1(int p,int v,int l=1,int r=n,int rt=1){ if(l==r){ tree[rt].mx = tree[rt].mn = v; tree[rt].add = 0; return; } pushdown(l,r,rt); int m = (l+r)>>1; if(p<=m) update1(p,v,Lson); else update1(p,v,Rson); pushup(rt);}void update2(int L,int R,int l=1,int r=n,int rt=1){ if(L<=l && R>=r){ tree[rt].add ^=1; solve(tree[rt].mx,tree[rt].mn); return; } pushdown(l,r,rt); int m = (l+r)>>1; if(L<=m) update2(L,R,Lson); if(R>m) update2(L,R,Rson); pushup(rt);}int query(int L,int R,int l=1,int r=n,int rt=1){ if(L<=l && R>=r) return tree[rt].mx; pushdown(l,r,rt); int m = (l+r)>>1; int ans = -INF; if(L<=m) ans = max(ans,query(L,R,Lson)); if(R>m) ans = max(ans,query(L,R,Rson)); pushup(rt); return ans;}//树剖int find(int u,int v){ int ans= -INF; while(top[u]!=top[v]){ if(dep[top[u]] dep[v]) swap(u,v); return max(ans,query(id[son[u]],id[v],1,n,1)); }void reverse(int u,int v){ while(top[u]!=top[v]){ if(dep[top[u]] dep[v]) swap(u,v); update2(id[son[u]],id[v],1,n,1);}int main(){ #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); #endif int T; scanf("%d",&T); while(T--){ init(); scanf("%d",&n); int u,v,w; for(int i=1;i