交換位置l,r,對答案產生的影響是l,r內(比l大的數個數-比l小的數個數)+(比r小的數個數-比r大的數的個數)+(l和r交換後應該+1或-1)。求這個東西用樹套樹就可以(做資料結構做傻了,還有很多其他優秀的做法)。
#include
#include
#include
#define maxn 1700005
using
namespace
std;
void read(int &a)
}int a[20005];
int lsh[20005];
struct xdstree[400005];
int n,m;
int val[maxn],sz[maxn];
int ch[maxn][2],fa[maxn];
int cnt[maxn],tot,d;
bool dir(int x)
void up(int x)
void rotate(int x)
void splay(int x,int e)
else
}}
}int nxt,t1;
int pre,t2;
void find_nxt(int p,int x)
}void insert(int f,int &x,int k)
if(val[x]==k)
sz[x]++;
insert(x,ch[x][val[x]void find(int x,int d)
}void del(int x,int d)
pre=-1;
find_pre(tree[d].rt,d);
splay(t2,tree[d].rt);
int c=ch[tree[d].rt][1];
ch[t2][1]=c;fa[c]=t2;
fa[t2]=0;tree[d].rt=t2;
up(t2);
}int pos;
void change(int x,int d)
int mid=(tree[x].l+tree[x].r)>>1;
if(mid>=pos)change(x<<1,d);
else change(x<<1|1,d);
}void build(int x,int l,int r)
int l,r,p1;
int ask(int x)
int mid=(tree[x].l+tree[x].r)>>1;
int ans=0;
if(mid>=l) ans+=ask(x<<1);
if(mid1|1);
return ans;
}int s[20005],top;
int ans;
struct tree_arr
return ans;
}void change(int x)
}void insert_arr()
}arr;
bool cmp(int a,int b)
void lsh()
}int main()
lsh();
printf("%d\n",ans);
build(1,1,n);
scanf("%d",&m);
int x,y;
for(int i=1;i<=m;i++)
return
0;}
BZOJ2141 排隊(線段樹套Treap)
點此看題面 大致題意 給你乙個序列,每次交換兩個數,求每次操作後的逆序對個數。推薦先去看一下這道題目 洛谷3759 tjoi2017 不勤勞的圖書管理員 貌似是此題的公升級版 推薦先去學一學線段樹套 treap 當然你也可以學習 hl666 奆佬分塊狂踩樹套樹 做了上面給出的那道題目,這道題目就是一...
bzoj 2141 排隊 (樹狀陣列套線段樹)
題目大意 給出乙個序列,每次交換兩個位置的數,求交換完後整個序列的逆序對數。對於乙個位置會產生的逆序對數是他前面比他大的數 他後面比他小的數。我們可以用樹狀陣列套線段樹維護一下,外層表示位置在樹狀陣列中該點的控制區間,線段樹是權值線段樹。然後每次交換完了計算一下就可以了。include includ...
bzoj2141 排隊(線段樹 splay)
題目鏈結 分析 之所以找到這道題是因為不想寫dp了 看到網上的題解都是 分塊 線段樹,樹狀陣列 線段樹。立志自己想解法 一開始我在想,能不能用cdq搞 但是cdq版的動態逆序對好像是單點修改 實際上逆序對的個數就是每個數字形成的逆序對之和 而每個數會和在ta之前比ta大的數以及在ta之後比ta大的數...