各种骚操作线段树

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;
}

  

以上是关于各种骚操作线段树的主要内容,如果未能解决你的问题,请参考以下文章

线段树详解

CF786B Legacy(线段树优化建图)

--目标--

●记录今日上午○线段树

线段树

决策树最骚操作