• 【GZOI2019】旧词


    题目链接:https://www.luogu.com.cn/problem/P5305

    题目大意:给定一棵有根树,已知常数 (k), 对于 (Q) 个询问 (x, y)(sumlimits_{i leq x} {depth(Lca(i, z))^k})

    solution

    (k = 1) 时, 显然就是原题【LN2014】LCA

    (k e 1) , 则可以进一步推广上一题的算法 , 对于每次修改点到根的权值分别加 1 其实就是对 (depth)的一种差分((depth(i) - depth(father(i)) = 1)) , 因此从根到节点路径上的权值之和即为节点深度

    现在依然可以将 (depth^k) 进行差分, 则若点 (i) 的深度为(dep_i) , 则 (i) 的权值每次应该增加 ({dep_i}^k - (dep_i - 1)^k) , 最后从根节点到节点的路径上的权值之和即为 ({dep_i}^k) , 可以先处理差分权值在(dfs)序区间上的前缀和 , 然后用树剖 + 线段树 , 离线进行修改与维护 , 具体做法同【LN2014】LCA

    时间复杂度: (O(nlog^2n))

    code

    #include<bits/stdc++.h>
    using namespace std;
    template <typename T> inline void read(T &FF) {
    	int RR = 1; FF = 0; char CH = getchar();
    	for(; !isdigit(CH); CH = getchar()) if(CH == '-') RR = -RR;
    	for(; isdigit(CH); CH = getchar()) FF = FF * 10 + CH - 48;
    	FF *= RR;
    }
    inline void file(string str) {
    	freopen((str + ".in").c_str(), "r", stdin);
    	freopen((str + ".out").c_str(), "w", stdout);
    }
    #define mod 998244353
    #define int long long
    const int N = 1e5 + 10;
    int now, fst[N], nxt[N], num[N], dep[N], n, q, k, sum[N];
    int p = 1, si, fa[N], tp[N], rev[N], sg[N], size[N], son[N], ans[N];
    void add(int u, int v) {
    	nxt[++now] = fst[u], fst[u] = now, num[now] = v;
    	nxt[++now] = fst[v], fst[v] = now, num[now] = u;
    }
    struct Segment_tree{
    	int val, tag;
    }xds[N << 2];
    struct Que{
    	int id, pi, qi;
    	friend bool operator < (Que ai, Que bi) {
    		return ai.pi < bi.pi;
    	}
    }qi[N];
    void push_up(int pos) {
    	xds[pos].val = (xds[pos << 1].val + xds[pos << 1 | 1].val) % mod;
    }
    void Add(int pos, int l, int r, int k) {
    	xds[pos].val = (xds[pos].val + k * ((sum[r] - sum[l - 1] + mod) % mod) % mod) % mod;
    	xds[pos].tag = (xds[pos].tag + k) % mod;
    }
    void push_down(int pos, int l, int r) {
    	if(xds[pos].tag == 0) return;
    	int mid = (l + r) >> 1;
    	Add(pos << 1, l, mid, xds[pos].tag);
    	Add(pos << 1 | 1, mid + 1, r, xds[pos].tag);
    	xds[pos].tag = 0;
    }
    void modify(int pos, int l, int r, int ll, int rr) {
    	if(l >= ll && r <= rr) {
    		Add(pos, l, r, 1);
    		return;
    	}
    	push_down(pos, l, r);
    	int mid = (l + r) >> 1;
    	if(mid >= ll) modify(pos << 1, l, mid, ll, rr);
    	if(mid < rr) modify(pos << 1 | 1, mid + 1, r, ll, rr);
    	push_up(pos);
    }
    int query(int pos, int l, int r, int ll, int rr) {
    	if(l >= ll && r <= rr) return xds[pos].val;
    	push_down(pos, l, r);
    	int mid = (l + r) >> 1, res = 0;
    	if(mid >= ll) res = (res + query(pos << 1, l, mid, ll, rr)) % mod;
    	if(mid < rr) res = (res + query(pos << 1 | 1, mid + 1, r, ll, rr)) % mod;
    	return res;
    }
    void fst_dfs(int xi) {
    	size[xi] = 1, dep[xi] = dep[fa[xi]] + 1;
    	for(int i = fst[xi]; i; i = nxt[i])
    		if(num[i] != fa[xi]) {
    			fst_dfs(num[i]);
    			size[xi] += size[num[i]];
    			if(size[num[i]] > size[son[xi]])
    				son[xi] = num[i];
    		}
    }
    void nxt_dfs(int xi) {
    	if(son[xi]) {
    		sg[++si] = son[xi], rev[son[xi]] = si;
    		tp[son[xi]] = tp[xi], nxt_dfs(son[xi]);
    	}
    	for(int i = fst[xi]; i; i = nxt[i])
    		if(num[i] != son[xi] && num[i] != fa[xi]) {
    			sg[++si] = num[i], rev[num[i]] = si;
    			tp[num[i]] = num[i], nxt_dfs(num[i]);
    		}
    }
    int Qpow(int ai, int ki) {
    	if(ki <= 1) return ki ? ai % mod : 1;
    	int hi = Qpow(ai, ki / 2); hi = hi * hi % mod;
    	return ki & 1 ? hi * ai % mod : hi;
    }
    void modify_list(int xi) {
    	while(xi) {
    		modify(1, 1, n, rev[tp[xi]], rev[xi]);
    		xi = fa[tp[xi]];
    	}
    }
    int query_list(int xi) {
    	int res = 0;
    	while(xi) {
    		res = (res + query(1, 1, n, rev[tp[xi]], rev[xi])) % mod;
    		xi = fa[tp[xi]];
    	}
    	return res;
    }
    signed main() {
    	//file("");	
    	read(n), read(q), read(k);
    	for(int i = 2; i <= n; i++)
    		read(fa[i]), add(fa[i], i);
    	si = tp[1] = rev[1] = sg[1] = 1;
    	fst_dfs(1), nxt_dfs(1);
    	for(int i = 1; i <= n; i++)
    		sum[i] = ((sum[i - 1] + Qpow(dep[sg[i]], k)) % mod - Qpow(dep[sg[i]] - 1, k) + mod) % mod;
    	for(int i = 1; i <= q; i++)
    		read(qi[i].pi), read(qi[i].qi), qi[i].id = i;
    	sort(qi + 1, qi + q + 1);
    	//cout << query(1, 1, n, rev[2], rev[2]) << endl;
    	for(int i = 1; i <= n; i++) {
    		modify_list(i);
    		//cout << query(1, 1, n, rev[3], rev[3]) << endl;
    		while(qi[p].pi == i)
    			ans[qi[p].id] = query_list(qi[p].qi), p++;
    	}
    	for(int i = 1; i <= q; i++) cout << ans[i] << endl;
    	return 0;
    }
    
  • 相关阅读:
    输入输出重定向
    MarkdownPad 2中编辑
    (转)Maven最佳实践:划分模块
    (转)maven设置内存
    我收集的sonar参考资料
    (转)linux service理解
    制作service服务,shell脚本小例子(来自网络)
    6
    4
    5
  • 原文地址:https://www.cnblogs.com/magicduck/p/12238897.html
Copyright © 2020-2023  润新知