HDU 4942 Game on S♂play(线段树、模拟、扩栈)

比赛的时候想到这题的大概做法,但由于卡别的水题。。。就赛后做了。。。

题意:给一个二叉树,每个结点有一个w[i],有3种操作,0 x表示左旋x,1 x表示右旋x,3 x表示询问x结点的价值,其中,价值为x子树结点的累加价值的累乘,其中,结点的累加价值为结点子树的Σw[i]。即询问是,∏Σw。

好像题意被我说得好渣好乱。。。。还是忽略上面2行吧。。。

首先,左旋右旋不影响中序遍历的index,即,可以把题目那2个图进行中序遍历,结果都是αXβYγ。由此,可以建立线段树。

而左旋右旋的过程模拟即可,可画示意图,将所有改变的一一写上。

要注意的是记得要改原本x跟父亲那条边,一开始没这个然后RE。。。。

  1 #pragma comment (linker,"/STACK:102400000,102400000")
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <iostream>
  5 using namespace std;
  6
  7 #define ll long long
  8 #define maxn 100010
  9 #define mod 1000000007
 10
 11 int son[maxn][2];
 12 int fa[maxn];
 13 int idx[maxn];
 14 int real[maxn];
 15 int lr[maxn][2];
 16 int w[maxn];
 17 ll val[maxn];
 18 ll mul[maxn<<2];
 19 void dfs(int x,int& dfn){
 20     val[x] = w[x];
 21     if(son[x][0]) dfs(son[x][0],dfn), lr[x][0]=lr[son[x][0]][0], val[x]+=val[son[x][0]];
 22     else lr[x][0]=dfn+1;
 23     idx[x] = ++dfn;
 24     real[dfn]=x;
 25     if(son[x][1]) dfs(son[x][1],dfn), lr[x][1]=lr[son[x][1]][1], val[x]+=val[son[x][1]];
 26     else lr[x][1]=dfn;
 27     val[x]%=mod;
 28 }
 29 void pushUp(int u){
 30     mul[u] = mul[u<<1]*mul[u<<1|1]%mod;
 31 }
 32 void build(int u,int l,int r){
 33     if(l==r){
 34         mul[u] = val[real[l]];
 35         return ;
 36     }
 37     int mid = (l+r)>>1;
 38     build(u<<1,l,mid);
 39     build(u<<1|1,mid+1,r);
 40     pushUp(u);
 41 }
 42 ll query(int u,int l,int r,int L,int R){
 43     if(l==L&&r==R) return mul[u];
 44     int mid = (l+r)>>1;
 45     if(R<=mid) return query(u<<1,l,mid,L,R);
 46     else if(L>mid) return query(u<<1|1,mid+1,r,L,R);
 47     return query(u<<1,l,mid,L,mid)*query(u<<1|1,mid+1,r,mid+1,R)%mod;
 48 }
 49 void update(int u,int l,int r,int pos,ll v){
 50     if(l==r){
 51         mul[u] = v;
 52         return ;
 53     }
 54     int mid = (l+r)>>1;
 55     if(pos<=mid) update(u<<1,l,mid,pos,v);
 56     else update(u<<1|1,mid+1,r,pos,v);
 57     pushUp(u);
 58 }
 59 void LR(int x,int op,int n){
 60     if(son[x][op]==0) return ;
 61     int y = son[x][op];
 62     int bb = son[y][op^1], cc=son[y][op];
 63     son[x][op]=bb;
 64     fa[bb]=x;
 65     int xx=fa[x];
 66     if(son[xx][0]==x) son[xx][0]=y;
 67     else son[xx][1]=y;
 68     fa[y]=xx;
 69     son[y][op^1]=x;
 70     fa[x]=y;
 71     if(bb) lr[x][op] = lr[bb][op];
 72     else lr[x][op] = idx[x];
 73     lr[y][op^1] = lr[x][op^1];
 74     if(bb) val[x] = val[x]-val[y]+val[bb];
 75     else val[x] = val[x]-val[y];
 76     if(cc) val[y] = val[x]+val[cc]+w[y];
 77     else val[y] = val[x]+w[y];
 78     update(1,1,n,idx[x],val[x]);
 79     update(1,1,n,idx[y],val[y]);
 80 }
 81 int main(){
 82     int t,n,m,ca=0;
 83     scanf("%d",&t);
 84     while(t--){
 85         printf("Case #%d:\n",++ca);
 86         scanf("%d%d",&n,&m);
 87         memset(fa,0,sizeof(fa));
 88         son[0][0]=son[0][1]=0;
 89         for(int i=1;i<=n;++i){
 90             scanf("%d%d%d",w+i,son[i],son[i]+1);
 91             fa[son[i][0]]=fa[son[i][1]]=i;
 92         }
 93         int dfn=0;
 94         dfs(1,dfn);
 95         build(1,1,n);
 96         for(int i=0;i<m;++i){
 97             int op,x;
 98             scanf("%d%d",&op,&x);
 99             if(op==2) printf("%I64d\n",query(1,1,n,lr[x][0],lr[x][1]));
100             else LR(x,op,n);
101         }
102     }
103     return 0;
104 }

HDU 4942 Game on S♂play(线段树、模拟、扩栈),布布扣,bubuko.com

时间: 2024-11-08 03:49:14

HDU 4942 Game on S♂play(线段树、模拟、扩栈)的相关文章

hdu 1394 Minimum Inversion Number(线段树)

Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 10853    Accepted Submission(s): 6676 Problem Description The inversion number of a given number sequence a1, a2, ..., a

HDU 4902 (牛叉的线段树)

Nice boat Problem Description There is an old country and the king fell in love with a devil. The devil always asks the king to do some crazy things. Although the king used to be wise and beloved by his people. Now he is just like a boy in love and c

HDU Wow! 4893 Such Sequence!(线段树)

HDU 4893 Wow! Such Sequence! 题目链接 题意:给定一个序列,3种操作,单点添加值,查询区间和,把区间和变成最接近的婓波那契数 思路:线段树,就是第三个操作麻烦,就在结点添加一个值,标记它区间是不是都是婓波那契数了,然后修改区间的时候,如果区间是了就不用修改,如果不是就继续往后一层推即可 代码: #include <cstdio> #include <cstring> #include <cstdlib> #define lson(x) ((x

HDU 4893 Wow! Such Sequence! 水线段树

思路: 线段树走起.. 写完这题就退役T^T 单点更新的时候直接找到这个点的最近fib,然后维护当前和 和 fib的和 #include<stdio.h> #include<string.h> #include<iostream> #include<math.h> #include<algorithm> #include<queue> #include<map> #include<set> #include&l

HDU 1754 I Hate It (线段树 单点更新)

题目链接 中文题意,与上题类似. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 #include <cstdlib> 6 #include <algorithm> 7 const int maxn = 200000+10; 8 using namespace std; 9 int a[maxn], n, m; 10

hdu 4893 Wow! Such Sequence!(线段树功能:单点更新,区间更新相邻较小斐波那契数)

转载请注明出处:http://blog.csdn.net/u012860063?viewmode=contents 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4893 --------------------------------------------------------------------------------------------------------------------------------------------

hdu 1698 Just a Hook 基本线段树

使用线段树更新每段区间的奖(1,2,3),最后在统计整段区间的数和,基本线段树,果断1A啊 #include<iostream> #include<stdio.h> using namespace std; #define N 100000 struct node{ int l,r,p; }a[N*4]; int n; void build(int left,int right,int i){ a[i].l=left; a[i].r=right; a[i].p=1; if(a[i]

hdu 1754:I Hate It(线段树,入门题,RMQ问题)

I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 33726    Accepted Submission(s): 13266 Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少.这让很多学生很反感.不管你喜不喜欢,现在需要你做的是,就是按照老师的要求

HDU 1394 Minimum Inversion Number(线段树求逆序数)

题目地址:HDU 1394 这题可以用线段树来求逆序数. 这题的维护信息为每个数是否已经出现.每次输入后,都从该点的值到n-1进行查询,每次发现出现了一个数,由于是从该数的后面开始找的,这个数肯定是比该数大的.那就是一对逆序数,然后逆序数+1.最后求完所有的逆序数之后,剩下的就可以递推出来了.因为假如目前的第一个数是x,那当把他放到最后面的时候,少的逆序数是本来后面比他小的数的个数.多的逆序数就是放到后面后前面比他大的数的个数.因为所有数都是从0到n-1.所以比他小的数就是x,比他大的数就是n-

HDU 1394 Minimum Inversion Number(线段树求最小逆序数对)

HDU 1394 Minimum Inversion Number(线段树求最小逆序数对) ACM 题目地址:HDU 1394 Minimum Inversion Number 题意: 给一个序列由[1,N]构成,可以通过旋转把第一个移动到最后一个. 问旋转后最小的逆序数对. 分析: 注意,序列是由[1,N]构成的,我们模拟下旋转,总的逆序数对会有规律的变化. 求出初始的逆序数对再循环一遍就行了. 至于求逆序数对,我以前用归并排序解过这道题:点这里. 不过由于数据范围是5000,所以完全可以用线