Codeforces 848C Goodbye Souvenir [CDQ分治,二維數點]
阿新 • • 發佈:2019-02-11
n) bug problem ret fine 你會 query while lower
。
洛谷
Codeforces
這題我寫了四種做法……
思路
不管做法怎樣,思路都是一樣的。
好吧,其實不一樣,有細微的差別。
第一種
考慮位置\(x\)對區間\([l,r]\)有\(\pm x\)的貢獻當且僅當\(pre_x\!\!<\!l \;or\;nxt_x\!\!>\!r\),其中\(pre,nxt\)表示與\(x\)同種顏色的前驅後繼。
那麽題目就轉化為二維數點了:一維是位置,一維是前驅/後繼,權值是\(\pm?\)位置。
第二種
考慮最後的減去開始的等價於每一位減去前面的。
即位置\(x\)的貢獻是\(x-pre_x,pre_x\geq l\)。
那麽題目同樣轉化為二維數點:一維是位置,一維是前驅,權值是\(x-pre_x\)
做法
做法一
按照第一種思路,暴力樹套樹。
然而這樣你會發現自己要麽MLE要麽RE……
做法二
按照第一種思路,莫隊+樹狀數組。
然而你會不停地TLE,而且我的卡常技巧不夠高超,放棄了。
做法三
按照第二種思路,莫隊+樹狀數組。
並不需要怎麽卡常就可以過。
嘿嘿,之前卡我莫隊,這次我卡你評測。
放幾張圖給大家瞧瞧:
中間那個25的是我的,其他是被我卡的/滑稽
做法四
這個是正解了。CDQ分治+二維數點。
但是太晚了,不想寫
留坑
代碼
做法一
#include<bits/stdc++.h> namespace my_std{ using namespace std; #define pii pair<int,int> #define fir first #define sec second #define MP make_pair #define rep(i,x,y) for (int i=(x);i<=(y);i++) #define drep(i,x,y) for (int i=(x);i>=(y);i--) #define go(x) for (int i=head[x];i;i=edge[i].nxt) #define sz 101010 typedef long long ll; template<typename T> inline void read(T& t) { t=0;char f=0,ch=getchar(); double d=0.1; while(ch>‘9‘||ch<‘0‘) f|=(ch==‘-‘),ch=getchar(); while(ch<=‘9‘&&ch>=‘0‘) t=t*10+ch-48,ch=getchar(); if(ch==‘.‘) { ch=getchar(); while(ch<=‘9‘&&ch>=‘0‘) t+=d*(ch^48),d*=0.1,ch=getchar(); } t=(f?-t:t); } template<typename T,typename... Args> inline void read(T& t,Args&... args){read(t); read(args...);} void file() { #ifndef ONLINE_JUDGE freopen("a.txt","r",stdin); #endif } // inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;} } using namespace my_std; int n,m; int a[sz]; int pre[sz],nxt[sz]; set<int>s[sz]; #define Tree sz*100 int Ls[Tree],Rs[Tree]; ll sum[2][Tree]; // 0:pre 1:nxt #define Lson Ls[k],l,mid #define Rson Rs[k],mid+1,r int cnt; int bin[Tree],top; void del(int &k){Ls[k]=Rs[k]=sum[0][k]=sum[1][k]=0;bin[++top]=k;k=0;} int newnode(){return top?bin[top--]:++cnt;} void Add(int &k,int l,int r,int x,int y,int t) { if (!k) k=newnode(); sum[t][k]+=y; if (l==r) { if (!sum[0][k]&&!sum[1][k]) del(k); return; } int mid=(l+r)>>1; if (x<=mid) Add(Lson,x,y,t); else Add(Rson,x,y,t); if (!sum[0][k]&&!sum[1][k]) del(k); } ll Query(int k,int l,int r,int x,int y,int t) { if (!k||x>y||!sum[t][k]) return 0; if (x<=l&&r<=y) return sum[t][k]; int mid=(l+r)>>1;ll ret=0; if (x<=mid) ret+=Query(Lson,x,y,t); if (y>mid) ret+=Query(Rson,x,y,t); return ret; } void Debug(int k,int l,int r,int t) { if (!k) { rep(i,l,r) printf("0 "); return; } if (l==r) return (void)printf("%lld ",sum[t][k]); int mid=(l+r)>>1; rep(i,0,1) assert(sum[i][k]==sum[i][Ls[k]]+sum[i][Rs[k]]); Debug(Lson,t);Debug(Rson,t); } #undef Lson #undef Rson int root[sz<<2]; #define ls k<<1 #define rs k<<1|1 #define lson ls,l,mid #define rson rs,mid+1,r ll query(int k,int l,int r,int x,int y) { if (x<=l&&r<=y) { ll a=Query(root[k],0,n+1,y+1,n+1,1),b=Query(root[k],0,n+1,0,x-1,0); return a-b; } int mid=(l+r)>>1;ll ret=0; if (x<=mid) ret+=query(lson,x,y); if (y>mid) ret+=query(rson,x,y); return ret; } void debug(int k,int l,int r) { printf("%d ~ %d:\n",l,r); printf("pre: ");Debug(root[k],0,n+1,0);puts(""); printf("nxt: ");Debug(root[k],0,n+1,1);puts(""); if (l==r) return; int mid=(l+r)>>1; debug(lson);debug(rson); } void change(int k,int l,int r,int x,int a,int b) // pre[x]->a , nxt[x]->b { if (pre[x]!=-1) Add(root[k],0,n+1,pre[x],-x,0); Add(root[k],0,n+1,a,x,0); if (nxt[x]!=-1) Add(root[k],0,n+1,nxt[x],-x,1); Add(root[k],0,n+1,b,x,1); if (l==r) return; int mid=(l+r)>>1; if (x<=mid) change(lson,x,a,b); else change(rson,x,a,b); } int calcPre(int x,int col){set<int>::iterator it=s[col].lower_bound(x);--it;return *it;} int calcNxt(int x,int col){return *(s[col].upper_bound(x));} int main() { file(); int x,y,z; read(n,m); rep(i,1,n) s[i].insert(0),s[i].insert(n+1); rep(i,1,n) read(a[i]),s[a[i]].insert(i); rep(i,1,n) { int Pre=calcPre(i,a[i]),Nxt=calcNxt(i,a[i]); pre[i]=nxt[i]=-1; change(1,1,n,i,Pre,Nxt); pre[i]=Pre,nxt[i]=Nxt; } while (m--) { read(z,x,y); if (z==1) { if (y==a[x]) continue; int Pre=calcPre(x,y),Nxt=calcNxt(x,y); change(1,1,n,x,Pre,Nxt); if (pre[x]!=0) change(1,1,n,pre[x],pre[pre[x]],nxt[x]); if (nxt[x]!=n+1) change(1,1,n,nxt[x],pre[x],nxt[nxt[x]]); if (Pre!=0) change(1,1,n,Pre,pre[Pre],x); if (Nxt!=n+1) change(1,1,n,Nxt,x,nxt[Nxt]); s[a[x]].erase(x);s[y].insert(x); a[x]=y; if (nxt[x]!=n+1) pre[nxt[x]]=pre[x]; if (pre[x]!=0) nxt[pre[x]]=nxt[x]; if (Pre!=0) nxt[Pre]=x; if (Nxt!=n+1) pre[Nxt]=x; pre[x]=Pre;nxt[x]=Nxt; } else printf("%lld\n",query(1,1,n,x,y)); } }
做法二
代碼被我瞎卡一波常數之後變得巨醜無比。
#include<bits/stdc++.h> namespace my_std{ using namespace std; #define rep(i,x,y) for (R int i=x;i<=y;++i) #define sz 101001 typedef long long ll; template<typename T> inline void read(T& t) { t=0;char f=0,ch=getchar(); double d=0.1; while(ch>‘9‘||ch<‘0‘) f|=(ch==‘-‘),ch=getchar(); while(ch<=‘9‘&&ch>=‘0‘) t=t*10+ch-48,ch=getchar(); if(ch==‘.‘) { ch=getchar(); while(ch<=‘9‘&&ch>=‘0‘) t+=d*(ch^48),d*=0.1,ch=getchar(); } t=(f?-t:t); } template<typename T,typename... Args> inline void read(T& t,Args&... args){read(t); read(args...);} void file() { #ifndef ONLINE_JUDGE freopen("a.txt","r",stdin); #endif } // inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;} } using namespace my_std; int n,m; int a[sz]; int pre[sz],nxt[sz]; int w[2][sz]; // 0:pre 1:nxt set<int>s[sz]; ll S1; ll sum[2][sz]; #define I inline #define R register I void Add(R int x,R ll v,R int t){S1+=v*t;while (x<=n+2) sum[t][x]+=v,x+=(x&(-x));} I ll Query(R int x,R int t){ll ret=0;while (x) ret+=sum[t][x],x-=(x&(-x));return ret;} ll ans[sz]; int blo; int pos[sz]; void init(){blo=pow(n,2.0/3);rep(i,1,sz-1) pos[i]=i/blo;} struct hh { int l,r,tim,id; I const bool operator < (const hh &a) const { if (pos[l]!=pos[a.l]) return pos[l]<pos[a.l]; if (pos[r]!=pos[a.r]) return pos[r]<pos[a.r]; return tim<a.tim; } }q[sz]; struct hhh { int pos,u,t; // t=0:pre t=1:nxt w[t][pos]->u inline hhh(int Pos=0,int U=0,int T=0){pos=Pos,u=U,t=T;} }p[sz*6]; I void swap(int &x,int &y){int t=x;x=y,y=t;} #define add(x) Add(w[0][x]+1,x,0);Add(w[1][x]+1,x,1); I void del(R int x){Add(w[0][x]+1,-x,0);Add(w[1][x]+1,-x,1);} I void work(R hhh &a,R int l,R int r) { R int pos=a.pos,t=a.t,&W=w[t][pos]; if (l<=pos&&pos<=r) Add(W+1,-pos,t); R int tt=a.u;a.u=W;W=tt; if (l<=pos&&pos<=r) Add(W+1,pos,t); } I int calcPre(R int x,R int col){set<int>::iterator it=s[col].lower_bound(x);--it;return *it;} I int calcNxt(R int x,R int col){return *(s[col].upper_bound(x));} signed main() { srand(time(0));rep(i,1,233) srand(rand()); file(); R int x,y,z; read(n,m); init(); rep(i,1,n) s[i].insert(0),s[i].insert(n+1); rep(i,1,n) read(a[i]),s[a[i]].insert(i); rep(i,1,n) w[0][i]=pre[i]=calcPre(i,a[i]),w[1][i]=nxt[i]=calcNxt(i,a[i]); R int tim=0,c=0; rep(_,1,m) { read(z,x,y); if (z==1) { if (y==a[x]) continue; int Pre=calcPre(x,y),Nxt=calcNxt(x,y); s[a[x]].erase(x);s[y].insert(x); a[x]=y; if (nxt[x]!=n+1) p[++tim]=hhh(nxt[x],pre[x],0),pre[nxt[x]]=pre[x]; if (pre[x]!=0) p[++tim]=hhh(pre[x],nxt[x],1),nxt[pre[x]]=nxt[x]; if (Pre!=0) p[++tim]=hhh(Pre,x,1),nxt[Pre]=x; if (Nxt!=n+1) p[++tim]=hhh(Nxt,x,0),pre[Nxt]=x; pre[x]=Pre;nxt[x]=Nxt; p[++tim]=hhh(x,Pre,0);p[++tim]=hhh(x,Nxt,1); } else ++c,q[c]=(hh){x,y,tim,c}; } sort(q+1,q+c+1); R int l=1,r=0;tim=0; rep(i,1,c) { R int L=q[i].l,RR=q[i].r,Tim=q[i].tim; while (tim<Tim) work(p[++tim],l,r); while (tim>Tim) work(p[tim--],l,r); while (l<L) {Add(w[0][l]+1,-l,0);Add(w[1][l]+1,-l,1);++l;} while (l>L) {--l;Add(w[0][l]+1,l,0);Add(w[1][l]+1,l,1);} while (r<RR) {++r;Add(w[0][r]+1,r,0);Add(w[1][r]+1,r,1);} while (r>RR) {Add(w[0][r]+1,-r,0);Add(w[1][r]+1,-r,1);--r;} ans[q[i].id]=S1-Query(RR+1,1)-Query(L-1+1,0); } rep(i,1,c) printf("%lld\n",ans[i]); }
做法三
#include<bits/stdc++.h>
namespace my_std{
using namespace std;
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define sz 101001
typedef long long ll;
template<typename T>
inline void read(T& t)
{
t=0;char f=0,ch=getchar();
double d=0.1;
while(ch>‘9‘||ch<‘0‘) f|=(ch==‘-‘),ch=getchar();
while(ch<=‘9‘&&ch>=‘0‘) t=t*10+ch-48,ch=getchar();
if(ch==‘.‘)
{
ch=getchar();
while(ch<=‘9‘&&ch>=‘0‘) t+=d*(ch^48),d*=0.1,ch=getchar();
}
t=(f?-t:t);
}
template<typename T,typename... Args>
inline void read(T& t,Args&... args){read(t); read(args...);}
void file()
{
#ifndef ONLINE_JUDGE
freopen("a.txt","r",stdin);
#endif
}
// inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;
int n,m;
int a[sz];
int pre[sz],nxt[sz];
int w[sz];
set<int>s[sz];
ll sum[sz];
//void add(int x,ll v){if (!x) return;while (x<=n) sum[x]+=v,x+=(x&(-x));}
//ll query(int x){ll ret=0;while (x) ret+=sum[x],x-=(x&(-x));return ret;}
void add(int x,ll v){sum[x]+=v;}
ll query(int x){ll ret=0;rep(i,1,x) ret+=sum[i];return ret;}
ll ans[sz];
int blo;
int pos[sz];
void init(){blo=pow(n,2.0/3);rep(i,1,sz-1) pos[i]=i/blo;}
struct hh
{
int l,r,tim,id;
const bool operator < (const hh &a) const
{
if (pos[l]!=pos[a.l]) return pos[l]<pos[a.l];
if (pos[r]!=pos[a.r]) return pos[r]<pos[a.r];
return tim<a.tim;
}
}q[sz];
struct hhh
{
int pos,v; // pre[pos] -> v
hhh(int Pos=0,int V=0){pos=Pos,v=V;}
}p[sz*6];
void add(int x){add(w[x],x-w[x]);}
void del(int x){add(w[x],w[x]-x);}
void work(hhh &a,int l,int r)
{
if (l<=a.pos&&a.pos<=r) add(w[a.pos],w[a.pos]-a.pos);
swap(a.v,w[a.pos]);
if (l<=a.pos&&a.pos<=r) add(w[a.pos],a.pos-w[a.pos]);
}
int calcPre(int x,int col){set<int>::iterator it=s[col].lower_bound(x);--it;return *it;}
int calcNxt(int x,int col){return *(s[col].upper_bound(x));}
int main()
{
file();
int x,y,z;
read(n,m);
init();
rep(i,1,n) s[i].insert(0),s[i].insert(n+1);
rep(i,1,n) read(a[i]),s[a[i]].insert(i);
int tim=0,c=0;
rep(i,1,n) w[i]=pre[i]=calcPre(i,a[i]),nxt[i]=calcNxt(i,a[i]);
while (m--)
{
read(z,x,y);
if (z==1)
{
if (y==a[x]) continue;
int Pre=calcPre(x,y),Nxt=calcNxt(x,y);
s[a[x]].erase(x);s[y].insert(x);
a[x]=y;
if (nxt[x]!=n+1)
pre[nxt[x]]=pre[x],
p[++tim]=hhh(nxt[x],pre[nxt[x]]);
if (pre[x]!=0) nxt[pre[x]]=nxt[x];
if (Pre!=0) nxt[Pre]=x;
if (Nxt!=n+1)
pre[Nxt]=x,
p[++tim]=hhh(Nxt,pre[Nxt]);
pre[x]=Pre;nxt[x]=Nxt;
p[++tim]=hhh(x,pre[x]);
}
else ++c,q[c]=(hh){x,y,tim,c};
}
sort(q+1,q+c+1);
int l=1,r=0;tim=0;
rep(i,1,c)
{
int L=q[i].l,R=q[i].r,Tim=q[i].tim;
while (tim<Tim) work(p[++tim],l,r);
while (tim>Tim) work(p[tim--],l,r);
while (l<L) del(l++);
while (l>L) add(--l);
while (r<R) add(++r);
while (r>R) del(r--);
ans[q[i].id]=query(n)-query(L-1);
}
rep(i,1,c) printf("%lld\n",ans[i]);
}
做法四
留坑
Codeforces 848C Goodbye Souvenir [CDQ分治,二維數點]