可修改主席樹
前面講完了主席樹,那現在就來考慮可修改的主席樹。
如果直接修改主席樹,我們就需要用
我們之所以前面的主席樹的修改時間如此大是因為每個
那麼可不可以用另外一種神奇的東西來使得
線段樹!!!
我是用樹狀陣列來實現的,每次的修改就沿著
下面附一下程式碼():
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<numeric>
#include<queue>
#include<functional>
#include<set>
#include<map>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define MAXN 100010
typedef double LL;
using namespace std;
struct node{
LL v1,v2,v3;
int v4;
int l,r,tot;
}tree[4000010];
int root[1010],tot,h[MAXN],f[11],k,n,m;
LL ans;
int get(){
char ch;
while (ch=getchar(),(ch<'0'||ch>'9')&& ch!='-' );
char c=ch;
int s;
if (c!='-')s=c-48;else s=0;
while (ch=getchar(),ch>='0'&&ch<='9')s=s*10+ch-48;
return c=='-'?-s:s;
}
void inse(int l,int r,int &t,int x,int y,int tim){
if (!t)t=++tot;
tree[t].tot+=tim;
if (l==r){
if (x>y){
tree[t].v1+=LL(1)/(x-y)*tim;
tree[t].v2+=LL(y)/(x-y)*tim;
tree[t].v3+=LL(y*y)/(x-y)*tim;
}
tree[t].v4+=(x+y)*tim;
return;
}
int mid=(l+r)/2;
if (x<=mid)inse(l,mid,tree[t].l,x,y,tim);
else inse(mid+1,r,tree[t].r,x,y,tim);
int ls=tree[t].l,rs=tree[t].r;
tree[t].v1=tree[ls].v1+tree[rs].v1;
tree[t].v2=tree[ls].v2+tree[rs].v2;
tree[t].v3=tree[ls].v3+tree[rs].v3;
tree[t].v4=tree[ls].v4+tree[rs].v4;
}
void add(int x,int y,int tim){
int y1=y;
while (y<1001){
inse(1,1001,root[y],x,y1,tim);
y=y+(y& -y);
}
}
void cc(int i,int x){
if (i<n){
if (h[i]>h[i+1])add(h[i],h[i+1],-1);
else add(h[i+1],h[i],-1);
if (x<h[i+1])add(h[i+1],x,1);
else add(x,h[i+1],1);
}
if (i>1){
if (h[i-1]>h[i])add(h[i-1],h[i],-1);
else add(h[i],h[i-1],-1);
if (x<h[i-1])add(h[i-1],x,1);
else add(x,h[i-1],1);
}
h[i]=x;
}
void getl(){
fo(i,1,k)f[i]=tree[f[i]].l;
}
void getr(){
fo(i,1,k)f[i]=tree[f[i]].r;
}
void getanswer(int l,int r,int x){
if (l>x){
fo(i,1,k)ans=ans+0.5*(tree[f[i]].v1*x*x-tree[f[i]].v2*x*2+tree[f[i]].v3);
return;
}
if (r<=x){
fo(i,1,k)ans=ans+tree[f[i]].tot*x-0.5*tree[f[i]].v4;
return;
}
int tt[11];
fo(i,1,k)tt[i]=f[i];
getl();
int mid=(l+r)/2;
getanswer(l,mid,x);
fo(i,1,k)f[i]=tt[i];
getr();
getanswer(mid+1,r,x);
}
void getans(int x){
k=0;
int y=x;
while (y){
f[++k]=root[y];
y=y-(y & -y);
}
ans=0;
getanswer(1,1001,x);
}
int main(){
n=get();m=get();
fo(i,1,n)h[i]=get()+1;
fo(i,1,n-1)
if (h[i]<h[i+1])add(h[i+1],h[i],1);
else add(h[i],h[i+1],1);
fo(i,1,m){
char ch;
while (ch=getchar(),ch!='Q'&&ch!='U');
if (ch=='Q'){
int x=get()+1;
getans(x);
printf("%.3lf\n",ans);
}
else{
int x=get()+1,y=get()+1;
cc(x,y);
}
}
}
相關推薦
可修改主席樹
前面講完了主席樹,那現在就來考慮可修改的主席樹。 如果直接修改主席樹,我們就需要用O(nlog2n)的時間來逐個逐個修改,那麼我們可否用更小的時間來修改呢? 我們之所以前面的主席樹的修改時間如此大是因為每個rooti的主席樹包含了root1,root2...
少年,想學帶修改主席樹嗎 | BZOJ1901 帶修改區間第k小
== write algo i++ sin esp 天下 read 一個 少年,想學帶修改主席樹嗎 | BZOJ1901 帶修改區間第k小 有一道題(BZOJ 1901)是這樣的:n個數,m個詢問,詢問有兩種:修改某個數/詢問區間第k小。 不帶修改的區間第k小用主席樹很好
[BZOJ 4826]影魔 區間修改主席樹 標記永久化
brush sca ostream www cpp pad stream i+1 return 為了這道題還特地去學了標記永久化,可能對於區間修改主席樹或者樹套樹比較有用吧OvO 我們可以把答案分為兩部分:p1造成的和p2造成的 我們枚舉序列,用單調棧求出序列每一個位置
待修改主席樹 (樹狀數組+主席樹)
scanf pos spa end tor cal pan name gin 終於學了這個我仰慕已久的算法。 對於待修改的主席樹我們只需要多開一維,進行修改後的求和。復雜度進化為O(nlog^2n) 我們需要開R0 L0兩個數組記錄樹狀數組的“路徑” 然後其他操作就和主席樹
hdu 4348 - 區間修改主席樹
題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=4348 題目連結: 時間倒流那肯定是主席樹啊,然後區間修改要用永久標記.下傳標記不能使用,空間會炸. #include <iostream>
[學習筆記]帶修改主席樹
1、Dynamic Rankings 區間帶修改的第 \(k\) 大需要用帶修改主席樹。 如果用平常的主席樹的效率是多少呢? 查詢 \(O(logn)\),暴力修改 \(O(nlogn)\),時間不支援 那麼就需要平衡一下兩者的時間複雜度 我們用樹狀陣列套主席樹,每次查詢把 \(logn\) 個 \
2112 動態單點修改主席樹
題目連結 題意:n個數,q個詢問 (n<=50000, q<=10000) Q x y z 代表詢問[x, y]區間裡的第z小的數 C x y 代表將(從左往右數)第x個數變成y 對於更新, 我們不改變這些已經建好的樹, 而是另建一批樹S
不帶修改主席樹模板
對於一部分線段樹看似無法直接做的題,可以用主席樹來做。 主席樹就是對每個字首開一棵線段樹,當然,直接這樣會MLE。 可以使用一種類似動態開節點的方法可以有效避免MLE。 具體可以參考我的部落格,那
HDU 2665.Kth number-無修改區間第K小-可持久化線段樹(主席樹)模板
sort ota nbsp ani show 去重 第k小 math urn Kth number Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Oth
可持久化線段樹(主席樹)模板
spa std nod d+ sin 整理 ostream pan int 比賽時候寫的,這裏整理到這裏 #include <iostream> #include <cstdio> #include <cstring> using
BZOJ 3674 可持久化並查集加強版(主席樹變形)
als ret desc scan sync scanf ops 只需要 ica 3673: 可持久化並查集 by zky Time Limit: 5 Sec Memory Limit: 128 MB Submit: 2515 Solved: 1107 [
不帶修改的主席樹
main ring ostream algorithm return else scan ons root #include<map> #include<stdio.h> #include<string.h> #include<v
主席樹(可持久化線段樹版)
可持久化線段樹 else init 修改 update 懶惰標記 logs scan amp 求區間和模板 1 struct node{ 2 int l[maxn*20],r[maxn*20]; //區間大小 maxn = 1e5時為20倍,不夠就開4
[poj2104]可持久化線段樹入門題(主席樹)
unique tor oot 入門題 個數 索引 方便 return 出現的次數 解題關鍵:離線求區間第k小,主席樹的經典裸題; 對主席樹的理解:主席樹維護的是一段序列中某個數字出現的次數,所以需要預先離散化,最好使用vector的erase和unique函數,很方便;如
【模板】可持久化線段樹 1(主席樹)
base math 一次 數據 mar 指定 das min 第k小 題目背景 這是個非常經典的主席樹入門題——靜態區間第K小 數據已經過加強,請使用主席樹。同時請註意常數優化 題目描述 如題,給定N個正整數構成的序列,將對於指定的閉區間
[Luogu] 可持久化線段樹 1(主席樹)
tdi ace oid root post space out 節點 nod https://www.luogu.org/problemnew/show/P3834 #include<cstdio> #include<iostream> #
【刷題】洛谷 P3834 【模板】可持久化線段樹 1(主席樹)
!= tchar 這樣的 信息 reg har mem hair define 題目背景 這是個非常經典的主席樹入門題——靜態區間第K小 數據已經過加強,請使用主席樹。同時請註意常數優化 題目描述 如題,給定N個正整數構成的序列,將對於指定的閉區間查詢其區間內的第K小值。
可持久化線段樹(主席樹)
AS string can -a 過程 思想 oot and amp 關於可持久化線段樹 可持久化線段樹可以將歷史版本的線段樹記憶下來,並支持新建版本與查詢歷史版本。 其中有一道經典的靜態主席樹的題就是求區間k大。 建樹的過程其實就是先建一棵空樹,再按輸入順序插入節點。需要
HDU 4348 To the moon(主席樹區間修改)
歷史 ons 證明 spa 產生 sin Go != 註意 題意 給你一個區間,支持如下操作: 在一段區間內加上一個值,並生成一個歷史版本 查詢某個版本下一段區間內的和 回到一個歷史版本上並舍棄之後的版本 做法 這就是主席樹區間修改裸題啦QwQ 上一篇博客我講了主席樹可
ZOJ -2112 Dynamic Rankings 主席樹 待修改的區間第K大
OS alt \n tar txt push fopen amp get Dynamic Rankings 帶修改的區間第K大其實就是先和靜態區間第K大的操作一樣。先建立一顆主席樹, 然後再在樹狀數組的每一個節點開線段樹(其實也是主席樹,共用節點), 每次修改的時候都按照