首页 > 代码库 > poj3468 线段树 or splay

poj3468 线段树 or splay

poj3468  裸线段树。因为在熟悉splay 所以就用splay交了一发。。。开始用的scanf()!==2 居然TLE了。。。然后我就当单组测试数据做的 然后就过了  囧TZ  

#include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>using namespace std;#define rt ch[root][1]#define lrt ch[rt][0]#define ls ch[x][0]#define rs ch[x][1]#define inf 0x3f3f3f3fconst int maxn=100100;int root,top;//root为新建节点时的根节点int ch[maxn][2],f[maxn];long long sz[maxn],num[maxn],val[maxn],sum[maxn],add[maxn];int n,m;//ch[x][0],ch[x][1]:x的左右儿子,f[x]:x的父亲节点,val[x]:x的值,sz[x]以x为根的子树的节点个数inline void pushup(int x){    sz[x]=sz[ls]+sz[rs]+1;    sum[x]=sum[ls]+sum[rs]+val[x];    //维护其他信息}inline void pushdown(int x){    if(add[x])    {        val[x]+=add[x];        add[ls]+=add[x];        add[rs]+=add[x];        sum[ls]+=(long long)(sz[ls]*add[x]);        sum[rs]+=(long long)(sz[rs]*add[x]);        add[x]=0;    }    //维护其他信息}inline void link(int y,int x,int d)//把节点y的(左或右)儿子设为x{    f[x]=y;    ch[y][d]=x;}inline int is(int x)//判断x为左儿子0还是右儿子1{    return ch[f[x]][1]==x;}inline void rotate(int x,int d){    int y=f[x];    int z=f[y];    pushdown(y);    pushdown(x);    link(y,ch[x][d],!d);    if(z) link(z,x,is(y));    f[x]=z;    link(x,y,d);    pushup(y);}inline void zag(int x){    rotate(x,0);}inline void zig(int x){    rotate(x,1);}inline void splay(int x,int goal=0)//第二个元素没有传参就默认为0,splay到0即将该节点旋转到根//将根为r的子树调整到x的父节点为goal的位置{    pushdown(x);    while(f[x]!=goal)    {        int y=f[x];        int z=f[y];        if(z==goal)        {            rotate(x,!is(x));            break;        }        if(ch[z][0]==y)        {            if(ch[y][0]==x) zig(y),zig(x);            else zag(x),zig(x);        }        else        {            if(ch[y][1]==x) zag(y),zag(x);            else zig(x),zag(x);        }    }    if(goal==0) root=x;    pushup(x);}//splay操作一般不做改动inline void newnode(int &x,int father,long long v){    x=++top;    f[x]=father;    val[x]=v;    add[x]=0;    ls=rs=0;    sz[x]=0;    //.....按题意建立信息}inline bool insert(int v){    int x=root;    while(ch[x][val[x]<v])    {        if(val[x]==v)        {            splay(x);            return false;        }        x=ch[x][val[x]<v];    }    newnode(ch[x][val[x]<v],x,v);    splay(ch[x][val[x]<v]);    return true;}inline void build(int &x,int y,int l,int r){    if(l>r) return ;    int mid=(l+r)>>1;    newnode(x,y,num[mid]);    build(ls,x,l,mid-1);    build(rs,x,mid+1,r);    pushup(x);}inline void init(int n){    root=top=0;    ch[0][0]=ch[0][1]=f[0]=val[0]=add[0]=sz[0]=sum[0]=0;    newnode(root,0,0);    newnode(rt,root,0);    sz[root]=2;    for(int i=0; i<n; i++) scanf("%lld",&num[i]);    build(lrt,rt,0,n-1);    pushup(rt);    pushup(root);    //for(int x=0;x<=top;x++){    //    printf("x=%d f[x]=%d ls=%d rs=%d val=%d sum=%d add=%d sz=%d\n",x,f[x],ls,rs,val[x],sum[x],add[x],sz[x]);    //}}inline int pre(int x)//获得前驱,调用时pre(root)即可{    x=ls;    if(x==0) return inf;    while(rs) x=rs;    return val[x];}inline int next(int x)//调用时next(root)即可,后继{    x=rs;    if(x==0) return inf;    while(ls) x=ls;    return val[x];}inline int get_k(int x,int k)//返回的是第k小的点的标号(从小到大),值要用val来获取{    pushdown(x);    int num=sz[ls]+1;    if(num==k) return x;    if(k<num) return get_k(ls,k);    return get_k(rs,k-num);}inline void update(){    int l,r;    long long c;    scanf("%d %d %lld",&l,&r,&c);    int x=get_k(root,l);    splay(x);    int y=get_k(root,r+2);    splay(y,root);    add[lrt]+=c;    sum[lrt]+=sz[lrt]*c;}//查询一段区间的值inline void query(){    int l,r;    scanf("%d%d",&l,&r);    int x,y;    x=get_k(root,l);    y=get_k(root,r+2);    splay(x);    splay(y,root);    printf("%lld\n",sum[lrt]);}int main(){    scanf("%d%d",&n,&m);    init(n);    for(int i=1;i<=m;i++){        int l,r,d;        char c;        scanf("%c%c",&c,&c);        if(c==Q){            //cout<<c<<endl;            query();        }        if(c==C){            update();        }    }}