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 0x3f3f3f3f const 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(); } } }
poj3468 线段树 or splay
时间: 2024-10-12 17:36:09