• 题解 星系探索


    题目传送门

    题目大意

    给出一个 (n) 个点的树,每个点有点权,有 (m) 次操作,分别为以下操作:

    • 将点 (x) 的父亲更改为 (y)

    • 将点 (u) 为根的子树内的点的点权一起增加 (w)

    • 查询点 (u) 到点 (1) 该链上的点的点权之和

    (nle 100000,mle 300000),保证答案在( ext{long long})范围以内。

    思路

    这似乎是个假的 ( ext{ETT}) ,似乎真的 ( ext{ETT}) 是用欧拉回路做的,但是它并不能维护链的信息,但可以支持换根。虽然还是没有 ( ext{Self-Adjusting Top Trees}) 强(尽管我完全不会(大喊 ( exttt{Tarjan}) 老爷子牛逼!!! 好了,还是来讲这道题吧

    我们发现其实难点就在于如何维护 (1 o u) 的链的点权和,我们可以发现其实这个可以用欧拉序(似乎也叫做括号序)维护,然后更改某个点的父亲其实可以用 ( ext{Splay}) 将该区间的欧拉序移到其它点下面去。然后我们惊奇地发现我们就做完了。

    时间复杂度 (Theta(n+mlog n)) ,为了方便我在前后各加了两个哨兵,能保证找到前驱后继。

    ( exttt{Code})

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define ll long long
    #define MAXN 200005
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    
    ll sum[MAXN],tag[MAXN];
    int n,m,root,son[MAXN][2],par[MAXN],val[MAXN],exi[MAXN],siz[MAXN];
    bool rnk (int x){return son[par[x]][1] == x;}
    void connect (int f,int now,int typ){son[par[now] = f][typ] = now;}
    void Pushup (int x){siz[x] = siz[son[x][0]] + siz[son[x][1]] + exi[x],sum[x] = sum[son[x][0]] + sum[son[x][1]] + val[x];}
    void Pushdown (int x){
    	if (tag[x]){
    		int ls = son[x][0],rs = son[x][1];
    		sum[ls] += siz[ls] * tag[x],sum[rs] += siz[rs] * tag[x];
    		if (ls) val[ls] += tag[x] * exi[ls];if (rs) val[rs] += tag[x] * exi[rs];
    		tag[ls] += tag[x],tag[rs] += tag[x],tag[x] = 0;
    	}
    }
    void rotate (int x){
    	int y = par[x],z = par[y],k = rnk (x),w = son[x][!k];
    	son[z][rnk (y)] = x,son[x][!k] = y,son[y][k] = w;
    	par[w] = y,par[x] = z,par[y] = x;
    	Pushup (y),Pushup (x); 
    }
    int tot,s[MAXN];
    void Splay (int x,int to){//将xSplay到to 
    	to = par[to];//Warning!!!
    	while (x) s[++ tot] = x,x = par[x];while (tot) Pushdown (s[tot --]);x = s[1];//整条链的懒标记下传 
    	for (Int y;par[x] ^ to;rotate (x)) if (par[y = par[x]] != to) rotate (rnk (x) == rnk (y) ? y : x);
    	if (!to) root = x;
    }
    void Query (int x){
    	Splay (x,root);
    	write (sum[son[x][0]] + val[x]),putchar ('
    ');
    }
    int pre (int x){
    	Splay (x,root);
    	x = son[x][0];while (son[x][1]) x = son[x][1];
    	return x;
    } 
    int suc (int x){
    	Splay (x,root);
    	x = son[x][1];while (son[x][0]) x = son[x][0];
    	return x;
    }
    void modify (int l,int r,ll v){
    	l = pre (l),r = suc (r);
    	Splay (r,root),Splay (l,son[r][0]);
    	int now = son[l][1];tag[now] += v,sum[now] += siz[now] * v,val[now] += exi[now] * v;
    	Pushup (l),Pushup (r);
    }
    void change (int l,int r,int to){//将[l,r]这段区间接到to的右子树 
    	l = pre (l),r = suc (r);
    	Splay (r,root),Splay (l,son[r][0]);
    	int now = son[l][1];par[now] = son[l][1] = 0;
    	Pushup (l),Pushup (r);int rs = suc (to);
    	Splay (rs,son[to][1]),connect (rs,now,0);
    	Pushup (rs),Pushup (to);
    }
    int Index = 1,top = 1,a[MAXN],to[MAXN],nxt[MAXN],head[MAXN],dfn[MAXN],low[MAXN];
    void Add_Edge (int u,int v){to[++ top] = v,nxt[top] = head[u],head[u] = top;} 
    void dfs (int u){
    	val[dfn[u] = ++ Index] = a[u],exi[Index] = 1;
    	for (Int i = head[u];i;i = nxt[i]) dfs (to[i]);
    	val[low[u] = ++ Index] = -a[u],exi[Index] = -1; 
    }
    int build (int l,int r){
    	if (l > r) return 0;
    	int mid = (l + r) >> 1;
    	par[son[mid][0] = build (l,mid - 1)] = par[son[mid][1] = build (mid + 1,r)] = mid;
    	return Pushup (mid),mid;
    }
    
    signed main(){
    	read (n);
    	for (Int i = 2,f;i <= n;++ i) read (f),Add_Edge (f,i);
    	for (Int i = 1;i <= n;++ i) read (a[i]);
    	dfs (1);root = build (1,++ Index);par[0] = 0;read (m);
    	for (Int i = 1,x,y;i <= m;++ i){
    		char s[3] = {};scanf ("%s",s);
    		if (s[0] == 'Q') read (x),Query (pre (low[x]));
    		else if (s[0] == 'C') read (x,y),change (dfn[x],low[x],dfn[y]);
    		else read (x,y),modify (dfn[x],low[x],y);
    	}
    	return 0;
    }
    
  • 相关阅读:
    关于区间 $mex$ 的几种做法
    Selenium+TestNG+Maven+Jenkins+SVN(转载)
    Selenium+Java的TestNG测试报告优化
    使用Log4J收集日志
    Selenium+TestNG+Maven(2)
    自动化测试用例设计实例
    自动化测试用例的编写规则
    selenium 总结篇,常见方法和页面元素的操作
    Selenium Webdriver元素定位的八种常用方式(转载)
    selenium+java利用AutoIT实现文件上传
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/13443033.html
Copyright © 2020-2023  润新知