各种骚操作线段树
Posted wang9897
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了各种骚操作线段树相关的知识,希望对你有一定的参考价值。
线段树是世界上最美的数据结构(主要记录一些有意义的线段树.....特别是骚操作
1.uestc1425 Another LCIS http://acm.uestc.edu.cn/#/problem/show/360
题意:两种操作 对于一段区间的数加上c 查询最长连续上升序列
题解:彻底弄清楚区间更新lazy的含义 就是切水题 直接区间更新然后区间合并用点小技巧即可
#include <iostream> #include <algorithm> #include <cstdio> #define N 100005 using namespace std; typedef struct node{ int l;int r;int l1;int len1;int r1;int len2; int len;int flag; }node; node d[N<<2]; int a[N]; void up(int root){ d[root].l1=d[root<<1].l1;d[root].r1=d[root<<1|1].r1; if(d[root<<1].r1<d[root<<1|1].l1){ d[root].len=max(d[root<<1].len,max(d[root<<1].len2+d[root<<1|1].len1,d[root<<1|1].len)); if(d[root<<1].len1==(d[root<<1].r-d[root<<1].l+1)) d[root].len1=d[root<<1].len1+d[root<<1|1].len1; else d[root].len1=d[root<<1].len1; if(d[root<<1|1].len2==(d[root<<1|1].r-d[root<<1|1].l+1)) d[root].len2=d[root<<1].len2+d[root<<1|1].len2; else d[root].len2=d[root<<1|1].len2; } else{ d[root].len=max(d[root<<1].len,d[root<<1|1].len); d[root].len1=d[root<<1].len1;d[root].len2=d[root<<1|1].len2; } } void push(int root){ d[root<<1].l1+=d[root].flag;d[root<<1].r1+=d[root].flag; d[root<<1|1].l1+=d[root].flag;d[root<<1|1].r1+=d[root].flag; d[root<<1].flag+=d[root].flag;d[root<<1|1].flag+=d[root].flag; d[root].flag=0; } void built(int root,int l,int r){ if(l==r){ d[root].l=l;d[root].r=r;d[root].l1=a[l];d[root].r1=a[l];d[root].len1=1;d[root].len2=1;d[root].len=1; d[root].flag=0; return ; } int mid=(l+r)>>1; built(root<<1,l,mid); built(root<<1|1,mid+1,r); d[root].l=d[root<<1].l;d[root].r=d[root<<1|1].r;d[root].flag=0;up(root); } void update(int root,int l,int r,int e){ if(l<=d[root].l&&d[root].r<=r){ d[root].flag+=e; d[root].l1+=e;d[root].r1+=e; return ; } push(root); int mid=(d[root].l+d[root].r)>>1; if(l<=mid) update(root<<1,l,r,e); if(r>mid) update(root<<1|1,l,r,e); up(root); } int ans;int tt;node ttt; void genxin(int root){ ttt.len=max(ttt.len,max(ttt.len2+d[root].len1,d[root].len)); if(ttt.len1==(ttt.r-ttt.l+1)) ttt.len1=ttt.len1+d[root].len1; else ttt.len1=ttt.len1; if(d[root].len2==(d[root].r-d[root].l+1)) ttt.len2=ttt.len2+d[root].len2; else ttt.len2=d[root].len2; ttt.r1=d[root].r1; } void querty(int root,int l,int r){ if(l<=d[root].l&&d[root].r<=r){ if(tt==0) {ans=d[root].len;ttt=d[root];} else{ // cout<<ttt.r1<<" "<<d[root].l1<<endl; if(ttt.r1<d[root].l1){ genxin(root); ans=max(ans,ttt.len); } else{ ans=max(ans,d[root].len);ttt=d[root]; } }tt=1; // cout<<d[root].l<<" "<<d[root].r<<" "<<ans<<endl; return ; } push(root); int mid=(d[root].l+d[root].r)>>1; if(l<=mid) querty(root<<1,l,r); if(r>mid) querty(root<<1|1,l,r); up(root); } int main(){ int Case=0;int T; // freopen("1.txt","r",stdin); scanf("%d",&T); char str[10]; while(T--){ int n,m;scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]); built(1,1,n); printf("Case #%d:\n",++Case); for(int i=1;i<=m;i++){ scanf("%s",str); int t1,t2,t3; if(str[0]==‘a‘){ scanf("%d%d%d",&t1,&t2,&t3); update(1,t1,t2,t3); } else if(str[0]==‘q‘){ scanf("%d%d",&t1,&t2); tt=0; querty(1,t1,t2); printf("%d\n",ans); } } } return 0; }
2.POJ 2991http://poj.org/problem?id=2991
题意:有n根棍子 每根棍子直接用一个节点相连 可旋转 有m种操作 即旋转s和s+1直接的节点 使节点成a角度 对于每次变化输出最后一个点的位置
题解:由向量旋转定理 对于增加的角度b 有x1=x0*cosb-y0*sinb;y1=sinb*x0+cosb*y0;然后线段树区间维护即可
#include <iostream> #include <algorithm> #include <queue> #include <vector> #include <map> #include <set> #include <cstdio> #include <cmath> #define N 20005 #define pi (acos(-1.0)) using namespace std; typedef struct node{ int l;int r;double t1,t2; int t; int flag; }node; node d[N<<2]; int a[N]; void upsh(int root){ d[root].t1=d[root<<1].t1+d[root<<1|1].t1; d[root].t2=d[root<<1].t2+d[root<<1|1].t2; } void built(int root,int l,int r){ if(l==r){ d[root].l=l;d[root].r=r;d[root].t1=0;d[root].t2=a[l]; d[root].flag=0;d[root].t=0; return ; } int mid=(l+r)>>1; built(root<<1,l,mid); built(root<<1|1,mid+1,r); d[root].l=d[root<<1].l;d[root].r=d[root<<1|1].r;upsh(root);d[root].flag=0; d[root].t=0; } void uppush(int root){ double tt=d[root].flag*1.0*pi/180; double ttt1,ttt2; d[root<<1].t=(d[root].flag+d[root<<1].t)%360;d[root<<1|1].t=(d[root].flag+d[root<<1|1].t)%360; d[root].t2=cos(tt)*ttt2+ttt1*sin(tt); ttt1=d[root<<1].t1; ttt2=d[root<<1].t2; d[root<<1].t1=ttt1*cos(tt)-ttt2*sin(tt); d[root<<1].t2=cos(tt)*ttt2+ttt1*sin(tt); ttt1=d[root<<1|1].t1; ttt2=d[root<<1|1].t2; d[root<<1|1].t1=ttt1*cos(tt)-ttt2*sin(tt); d[root<<1|1].t2=cos(tt)*ttt2+ttt1*sin(tt); d[root<<1].flag=(d[root<<1].flag+d[root].flag)%360;d[root<<1|1].flag=(d[root<<1|1].flag+d[root].flag)%360; d[root].flag=0; } void update(int root,int l,int r,int e){ if(l<=d[root].l&&d[root].r<=r){ d[root].flag=(d[root].flag+e)%360;d[root].t=(d[root].t+e)%360; double tt=e*1.0*pi/180; double ttt1=d[root].t1; double ttt2=d[root].t2; d[root].t1=ttt1*cos(tt)-ttt2*sin(tt); d[root].t2=cos(tt)*ttt2+ttt1*sin(tt); return ; } uppush(root); int mid=(d[root].l+d[root].r)>>1; if(l<=mid) update(root<<1,l,r,e); if(r>mid) update(root<<1|1,l,r,e); upsh(root); } int ans; void querty(int root,int e){ if(d[root].l==d[root].r){ ans=d[root].t; return ; } uppush(root); int mid=(d[root].l+d[root].r)>>1; if(e<=mid) querty(root<<1,e); else querty(root<<1|1,e); upsh(root); } int main(){ int n,m; int Case=0; while(scanf("%d%d",&n,&m)==2){ for(int i=1;i<=n;i++) scanf("%d",&a[i]); built(1,1,n); int t1,t2; if(Case++!=0) puts(""); for(int i=1;i<=m;i++){ scanf("%d%d",&t1,&t2); querty(1,t1); int ans1=ans; querty(1,t1+1); int ans2=ans; int t=(t2-((180+ans2-ans1+360)%360))%360; update(1,t1+1,n,t); printf("%.2lf %.2lf\n",d[1].t1,d[1].t2); } } return 0; }
以上是关于各种骚操作线段树的主要内容,如果未能解决你的问题,请参考以下文章