标签:bzoj 树套树 线段树套treap cqoi 2011 卡常
题目大意:给出一个数列,每次从这个序列中删掉一个数字,问每次删之前逆序对的数量是多少。
思路:这个题用CDQ分治是飞快的,然而我不知道怎么写。。于是就朴素的写了树套树。然后就朴素的被卡常了
内层用一个线段树。这个线段树不修改,一开始就要建好,然后线段树的每一个节点维护一个平衡树,存的是线段树存的区间中所有的值。
一开始先算一下逆序对数,然后每次删点的时候,先查询在这个点之前有多少大于他的,后面有多少小于他的,总的逆序对中将这些减掉。这个过程通过树套树不难实现。
CODE(交了这个代码T掉的,请选择在人多的时候先交一发糖果公园再交一次本题即可。。。因为多人测的时候会放宽一点时限。。。
你们感受一下
):
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 100010 using namespace std; #define LEFT (pos << 1) #define RIGHT (pos << 1|1) #define SIZE(a) ((a) == NULL ? 0:a->size) namespace IStream{ const int L=1<<15; char buffer[L],*S,*T; inline char Get_Char() { if(S==T) { T=(S=buffer)+fread(buffer,1,L,stdin); if(S==T) return EOF; } return *S++; } inline int GetInt() { char c; int re=0; for(c=Get_Char();c<'0'||c>'9';c=Get_Char()); while(c>='0'&&c<='9') re=(re<<1)+(re<<3)+(c-'0'),c=Get_Char(); return re; } } /*class OStream{ private: static const int L=1<<15; char stack[20];int top; char buffer[L],*S; public: OStream() { S=buffer; } void PutLongLong(long long x) { stack[++top]='\n'; if(!x) stack[++top]='0'; else while(x) stack[++top]=x%10+'0',x/=10; while(top) { if(S==buffer+L-1) { printf("%s",buffer); S=buffer; } *S++=stack[top--]; } } ~OStream() { *S=0; puts(buffer); } }os;*/ int cnt,asks; int src[MAX],pos[MAX]; int fenwick[MAX]; long long inv; struct Treap{ int random,val,size; Treap *son[2]; Treap(int _) { val = _; random = rand(); size = 1; son[0] = son[1] = NULL; } int Compare(int x) { if(x == val) return -1; return x > val; } void Maintain() { size = 1; if(son[0] != NULL) size += son[0]->size; if(son[1] != NULL) size += son[1]->size; } }*tree[MAX << 2]; inline int GetSum(int x) { int re = 0; for(; x < MAX; x += x&-x) re += fenwick[x]; return re; } inline void Fix(int x,int c) { for(; x; x -= x&-x) fenwick[x] += c; } inline void Rotate(Treap *&a,bool dir) { Treap *k = a->son[!dir]; a->son[!dir] = k->son[dir]; k->son[dir] = a; a->Maintain(),k->Maintain(); a = k; } void Insert(Treap *&a,int x) { if(a == NULL) { a = new Treap(x); return ; } int dir = a->Compare(x); Insert(a->son[dir],x); if(a->son[dir]->random > a->random) Rotate(a,!dir); a->Maintain(); } void Delete(Treap *&a,int x) { int dir = a->Compare(x); if(dir != -1) Delete(a->son[dir],x); else { if(a->son[0] == NULL) a = a->son[1]; else if(a->son[1] == NULL) a = a->son[0]; else { int _ = (a->son[0]->random > a->son[1]->random); Rotate(a,_); Delete(a->son[_],x); } } if(a != NULL) a->Maintain(); } int Ask(Treap *a,int x) { if(a == NULL) return 0; if(a->val > x) return Ask(a->son[0],x); if(a->val == x) return SIZE(a->son[0]); return SIZE(a->son[0]) + 1 + Ask(a->son[1],x); } void BuildTree(int l,int r,int pos) { for(int i = l; i <= r; ++i) Insert(tree[pos],src[i]); if(l == r) return ; int mid = (l + r) >> 1; BuildTree(l,mid,LEFT); BuildTree(mid + 1,r,RIGHT); } void Delete(int l,int r,int x,int pos,int c) { Delete(tree[pos],c); if(l == r) return ; int mid = (l + r) >> 1; if(x <= mid) Delete(l,mid,x,LEFT,c); else Delete(mid + 1,r,x,RIGHT,c); } int Ask(int l,int r,int x,int y,int pos,int c) { if(l == x && y == r) return Ask(tree[pos],c); int mid = (l + r) >> 1; if(y <= mid) return Ask(l,mid,x,y,LEFT,c); if(x > mid) return Ask(mid + 1,r,x,y,RIGHT,c); int left = Ask(l,mid,x,mid,LEFT,c); int right = Ask(mid + 1,r,mid + 1,y,RIGHT,c); return left + right; } int main() { srand(19970815); cin >> cnt >> asks; for(int i = 1; i <= cnt; ++i) { src[i] = IStream::GetInt(); //scanf("%d",&src[i]); pos[src[i]] = i; inv += GetSum(src[i]); Fix(src[i],1); } BuildTree(1,cnt,1); memset(fenwick,0,sizeof(fenwick)); for(int i = 1; i <= cnt; ++i) Fix(i,1); for(int x,i = 1; i <= asks; ++i) { printf("%lld\n",inv); //os.PutLongLong(inv); x = IStream::GetInt(); //scanf("%d",&x); Delete(1,cnt,pos[x],1,x); Fix(pos[x],-1); if(pos[x] != 1) inv -= (GetSum(1) - GetSum(pos[x]) - Ask(1,cnt,1,pos[x] - 1,1,x)); if(pos[x] != cnt) inv -= Ask(1,cnt,pos[x] + 1,cnt,1,x); } return 0; }
BZOJ 3295 CQOI 2011 动态逆序对 线段树套Treap
标签:bzoj 树套树 线段树套treap cqoi 2011 卡常
原文地址:http://blog.csdn.net/jiangyuze831/article/details/42104595