樹狀數組【洛谷P3586】 [POI2015]LOG
阿新 • • 發佈:2018-11-01
sig str sin 但是 scanf add char scan ons
P3586 [POI2015]LOG
維護一個長度為n的序列,一開始都是0,支持以下兩種操作:1.U k a 將序列中第k個數修改為a。2.Z c s 在這個序列上,每次選出c個正數,並將它們都減去1,詢問能否進行s次操作。每次詢問獨立,即每次詢問不會對序列進行修改。
離散化按照權值建立樹狀數組。
那麽對於大於s的值,可以直接減去s,這一部分的貢獻為\(c*(query_{geshu}(tot)-query_{geshu}(s-1))\)。
剩下的數,我們只知道他們小於s,但是不知道確切的值所以並不能用上述方法求出貢獻。
但是我們知道每個數的大小,那麽可以求出每個數的權值*個數之和,這些是可以作為貢獻的。
也就是\(query_{quanzhi}(s-1)\)。
註意離散化。
對於離散化,一定註意當前的值要用離散化之後的還是之前的。
之後的用\(lowerbound\)求出,之後的再用求出的序號帶入到離散化數組就可以。
code:
#include <iostream> #include <cstdio> #include <algorithm> #define int long long using namespace std; const int wx=3000017; inline int read(){ int sum=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0'; ch=getchar();} return sum*f; } int a[wx],sum_geshu[wx],sum_quanzhi[wx],b[wx]; int n,m,tot; int c[wx]; char opt[7]; struct node{ int flag,num,to; int c,s; }t[wx]; void add1(int pos,int k){ for(int i=pos;i<=tot;i+=(i&-i)) sum_geshu[i]+=k; } int query1(int pos){ int re=0; for(int i=pos;i>=1;i-=(i&-i)) re+=sum_geshu[i]; return re; } void add2(int pos,int k){ for(int i=pos;i<=tot;i+=(i&-i)) sum_quanzhi[i]+=k; } int query2(int pos){ int re=0; for(int i=pos;i>=1;i-=(i&-i)) re+=sum_quanzhi[i]; return re; } signed main(){ n=read(); m=read(); for(int i=1;i<=m;i++){ scanf("%s",opt+1); if(opt[1]=='U'){ t[i].flag=1; t[i].num=read(); t[i].to=read(); b[++tot]=t[i].to; } else{ t[i].c=read(); t[i].s=read(); b[++tot]=t[i].s; } } sort(b+1,b+1+tot); for(int i=1;i<=m;i++){ if(t[i].flag){ int tmp=lower_bound(b+1,b+1+tot,t[i].to)-b; if(a[t[i].num]){ add1(a[t[i].num],-1);add2(a[t[i].num],-b[a[t[i].num]]); } if(tmp){ add1(tmp,1); a[t[i].num]=tmp; add2(tmp,b[tmp]); } } else{ int s=lower_bound(b+1,b+1+tot,t[i].s)-b; int tmp=b[s]*(t[i].c-(query1(tot)-query1(s-1))); if(tmp<=query2(s-1))puts("TAK"); else puts("NIE"); } } return 0; }
樹狀數組【洛谷P3586】 [POI2015]LOG