BZOJ3626 LCA

来源:互联网 发布:清空表数据 编辑:程序博客网 时间:2024/05/22 09:06

给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。

设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。

有q次询问,每次询问给出l r z,求sigma_{l<=i<=r}dep[LCA(i,z)]。(即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和)

n<=50000



一开始无从下笔,知道肯定要用到离线算法,不过没有想到如何体现离线的思想。

其实之前做过一道类似的树上区间询问-修改类型的题,那道题是把询问端点排序,然后左端点进入的时候记录一个值,右端点弹出的时候用新计算的值减去原来左端点计算的值,从而得到区间的答案。

没有想到,看了题解才明白大概怎么搞。于是树链剖分水过。


数据结构题要保证1A率。本题1A。


#include       <map>#include       <set>#include     <cmath>#include     <ctime>#include     <queue>#include    <cstdio>#include    <vector>#include    <string>#include    <bitset>#include   <cstring>#include   <cstdlib>#include  <iostream>#include <algorithm>using namespace std;#ifndef unix    #define lld "%I64d"    #define llu "%I64u"#else    #define lld "%lld"    #define llu "%llu"#endif#define FOR(a,b,c)  for(int (a)=b;(a)<=(c);++(a))#define FORD(a,b,c) for(int (a)=b;(a)>=(c);--(a))#define FORV(a,t,b) for(vector<t>::iterator a=b.begin();a!=b.end();++a)#define MAX(a,b)                   a=max(a,b)#define MIN(a,b)                   a=min(a,b)#define BLA                      printf("\n")#define pb                          push_back#define mp                          make_pair#define gc                            getchar#define RT                             return#define BB                             second#define AA                              first#define bk                              break#define LINF             0x3f3f3f3f3f3f3f3fll#define INF                        0x3f3f3f3f#define eps                              1e-8#define DINF                             1e20//#define Generatortypedef long long           ll;typedef unsigned            ui;typedef unsigned long long ull;typedef pair<int,int>      pii;typedef pair<ll ,ll >      pll;const int MAXN= 50005;const int MOD = 201314;template <class T> inline void CLR(T &g)             {T t;swap(t,g);}template <class T> inline void CLR(T &g,int a){memset(g,a,sizeof g);}template <class T> inline void CPY(T &a,T &b) {memcpy(a,b,sizeof a);}template <class T> inline bool inr(T a,T b,T c)  {RT (a>=b && a<=c);}inline int acc(int a,int b)                    {RT !!(a & (1<<b-1));}inline int fil(int a,int b,int c)    {RT a & ~(1<<b-1) | (1<<b-1)*c;}int N,M,K,Q;class seg{public:struct node{ll key, tag;int l, r;node *lc,*rc;node(){lc= rc= NULL;key= tag= l= r= 0;}}*root;void build(int l, int r, node *x){x->l=l; x->r=r;if (l==r) RT;x->lc= new node; x->rc= new node;build(l, (l+r)/2, x->lc);build((l+r)/2+1,r,x->rc);}void init(int N){root=new node;build(1, N, root);}void pushdown(node *x){if (x->tag){if (x->lc)x->lc->key += x->tag*(x->lc->r-x->lc->l+1), x->rc->key += x->tag*(x->rc->r-x->rc->l+1),x->lc->tag += x->tag, x->rc->tag += x->tag;x->tag = 0;}}void update(int l, int r, node *x){pushdown(x);if (l==x->l && r==x->r){x->tag++; x->key += x->r-x->l+1;RT;}if (l>=x->rc->l) update(l, r, x->rc);else if (r<=x->lc->r) update(l, r, x->lc);else update(l, x->lc->r, x->lc), update(x->rc->l, r, x->rc);x->key = x->lc->key + x->rc->key;}ll query(int l, int r, node *x){pushdown(x);if (l==x->l && r==x->r) RT x->key;if (l>=x->rc->l) RT query(l, r, x->rc);if (r<=x->lc->r) RT query(l, r, x->lc);RT query(l, x->lc->r, x->lc)+query(x->rc->l, r, x->rc);}void update(int l, int r){if (l>r) RT;update(l, r, root);}ll query(int l, int r){if (l>r) RT -1;RT query(l, r, root);}}s;int segcur;struct node{int fa;vector <int> s;int siz, bel, num;//子树大小 从属的重链顶编号 线段树中的节点编号int heavy;}t[MAXN];ll ans[MAXN];struct query{int p, q;//区间节点为p  待查询节点为qint flg;//0表示是左端点  1表示是右端点int num;//询问编号为numbool operator <(const query &a)const{RT p<a.p;}}q[MAXN<<1];int dfs1(int u){t[u].siz=1;int Max=0;FORV(i, int, t[u].s){t[u].siz += dfs1(*i);if (t[*i].siz>t[Max].siz) Max=*i;}t[u].heavy=Max;//重儿子RT t[u].siz;}int dfs2(int u, int top=0){//如果top没有赋值  说明是轻链顶端if (!top) top=u;t[u].num = ++segcur;t[u].bel = top;if (t[u].heavy) dfs2(t[u].heavy, top);FORV(i, int, t[u].s){if ((*i)==t[u].heavy) continue;dfs2(*i);}}//树链剖分操作void Update(int p){//把p到根这条路径上的权值加1while (p){s. update(t[t[p].bel].num, t[p].num);p=t[t[p].bel].fa;}}ll Query(int p){//求p到根这条路径上的权值和ll ans=0;while (p){ans += s. query(t[t[p].bel].num, t[p].num);p=t[t[p].bel].fa;}RT ans;}int main(){#ifndef Generator#ifndef ONLINE_JUDGEfreopen("input.txt" ,"r",stdin );freopen("output.txt","w",stdout);#endif#endif#ifdef Generatorfreopen("input.txt","w",stdout);srand((ui)time(NULL));#endifint T,o=0;scanf("%d%d",&N,&Q);s.init(N);FOR(i,2,N){int k;scanf("%d",&k); ++k;t[i].fa=k; t[k].s.pb(i);}dfs1(1); dfs2(1);FOR(i,1,Q){int l,r,z;scanf("%d%d%d",&l,&r,&z);++l; ++r; ++z;q[i*2-1]=(query){l-1, z, 0, i};q[i*2]  =(query){r,   z, 1, i};}sort(q+1,q+1+Q*2);int cur=0;FOR(i,1,Q*2){while (cur < q[i].p) Update(++cur);if (q[i].flg==0) ans[q[i].num]=Query(q[i].q);else ans[q[i].num]=(Query(q[i].q)-ans[q[i].num])%MOD;}FOR(i,1,Q)printf(lld"\n", ans[i]);RT 0;}


0 0
原创粉丝点击