HDU 6356 Glad You Came(st表/線段樹/單調佇列)
阿新 • • 發佈:2019-02-11
題目連結
題意:
Let the i-th result value of calling the above function as The i-th operation of Steve is to update aj as vi if , where
一開始給你一個序列a,裡面全是0,然後有m次操作,每次操作給你[l,r],v,更新[l,r]區間,將所有區間內小於v的元素都改成v
每次操作的變數由上面那個式子產生,裡面的f是由上面那個隨機數函式產生
解析:
這道題......m這麼大,連排序都不能排.......竟然能用最裸的線上更新的線段樹過..........這也太坑了把..........
官方題解好像使用st表來做的
如果有兩個操作覆蓋相同的區間,我們可以保留最大的那個。對於每個操作,令d等於⌊log2(r−l+1)⌋
我們可以用兩個操作和替換此操作。這樣做之後,每個操作所覆蓋的區間長度均為 2 的冪,這意味著長度僅有 種。剩下的只不過是,按長度遞減的順序列舉操作,將每個操作分成兩個相等長度的操作,直到區間長度為一。這樣做的時間複雜度為 ,空間複雜度為。
其實就是把詢問的區間都分成2的冪次的長度,這樣長度最多隻有種,然後再用逆的st表做就可以了
st表好像要3.2s。。。。
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned int ui; #define pb push_back const int MAXN = 1e5+10; const int MAXM = 5e6+10; const ll INF = 0x3f3f3f3f; ui X,Y,Z; ui f[4*MAXM]; int a[MAXN]; typedef struct interval { int L; int v; }interval; int mq[50][MAXN]; int two[50]; interval hq[MAXN]; int Log[MAXN]; inline ui RNG61() { X=X^(X<<11); X=X^(X>>4); X=X^(X<<5); X=X^(X>>14); ui W=X^(Y^Z); X=Y; Y=Z; Z=W; return Z; } int main() { int t; int kk=1<<30; scanf("%d",&t); int tmp=1; Log[1]=0; Log[2]=1; for(int i=0;i<=20;i++) two[i]=tmp,tmp=tmp<<1; for(int i=3;i<MAXN;i++) Log[i]=Log[i>>1]+1; //log2預處理 while(t--) { ll n,m; scanf("%lld%lld%u%u%u",&n,&m,&X,&Y,&Z); int kkk=Log[n]; for(int i=0;i<=n;i++) a[i]=0; for(int i=0;i<=kkk;i++) for(int j=1;j<=n;j++) mq[i][j]=0; for(int i=1;i<=3*m;i++) { f[i]=RNG61(); } for(int i=1;i<=m;i++) { int l=min((f[3*i-2]%n)+1,(f[3*i-1]%n)+1); int r=max((f[3*i-2]%n)+1,(f[3*i-1]%n)+1); int v=f[3*i]%kk; int d=Log[r-l+1]; mq[d][l]=mq[d][l]<v?v:mq[d][l]; mq[d][r-two[d]+1]=mq[d][r-two[d]+1]<v?v:mq[d][r-two[d]+1]; } for(int i=kkk;i>0;i--) { for(int j=1;j<=n;j++) { if(j+two[i-1]>n) break; mq[i-1][j]=max(mq[i-1][j],mq[i][j]); mq[i-1][j+two[i-1]]=max(mq[i-1][j+two[i-1]],mq[i][j]); } } ll ans=0; for(ll i=1;i<=n;i++) { ans=ans^(i*mq[0][i]); } printf("%lld\n",ans); } return 0; }
我一開始是用單調佇列代替st表的,然後必須把log進行預處理,常數優化才能過....3.3s
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned int ui; #define pb push_back const int MAXN = 1e5+10; const int MAXM = 5e6+10; const ll INF = 0x3f3f3f3f; ui X,Y,Z; ui f[4*MAXM]; int a[MAXN]; typedef struct interval { int L; int v; }interval; int mq[50][MAXN]; int two[50]; interval hq[MAXN]; int Log[MAXN]; inline ui RNG61() { X=X^(X<<11); X=X^(X>>4); X=X^(X<<5); X=X^(X>>14); ui W=X^(Y^Z); X=Y; Y=Z; Z=W; return Z; } int main() { int t; int kk=1<<30; scanf("%d",&t); int tmp=1; Log[1]=0; Log[2]=1; for(int i=0;i<=20;i++) two[i]=tmp,tmp=tmp<<1; for(int i=3;i<MAXN;i++) Log[i]=Log[i>>1]+1; //log2預處理 while(t--) { ll n,m; scanf("%lld%lld%u%u%u",&n,&m,&X,&Y,&Z); int kkk=Log[n]; for(int i=0;i<=n;i++) a[i]=0; for(int i=0;i<=kkk;i++) for(int j=1;j<=n;j++) mq[i][j]=0; for(int i=1;i<=3*m;i++) { f[i]=RNG61(); } for(int i=1;i<=m;i++) { int l=min((f[3*i-2]%n)+1,(f[3*i-1]%n)+1); int r=max((f[3*i-2]%n)+1,(f[3*i-1]%n)+1); int v=f[3*i]%kk; int d=Log[r-l+1]; mq[d][l]=mq[d][l]<v?v:mq[d][l]; mq[d][r-two[d]+1]=mq[d][r-two[d]+1]<v?v:mq[d][r-two[d]+1]; } int head,tail; head=tail=0; for(int i=kkk;i>=0;i--) { head=tail=0; for(int j=1;j<=n;j++) { while(head<tail&&hq[tail-1].v<=mq[i][j]) tail--; hq[tail++]=interval{j,mq[i][j]}; if(head<tail) a[j]=max(hq[head].v,a[j]); if(j-two[i]+1>=1) { while(head<tail&&hq[head].L<=j-two[i]+1) head++; } } } ll ans=0; for(ll i=1;i<=n;i++) { ans=ans^(i*a[i]); } printf("%lld\n",ans); } return 0; }
最裸的線段樹,2.9s.......這個是最快的
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
#define lch root<<1
#define rch root<<1|1
typedef unsigned int ui;
typedef long long ll;
const int MAXN = 1e5+10;
const int MAXM = 5e6+10;
const ll INF = 0x3f3f3f3f;
ui X,Y,Z;
ui f[4*MAXM];
int a[MAXN];
int Btree[MAXN*4];
inline ui RNG61()
{
X=X^(X<<11);
X=X^(X>>4);
X=X^(X<<5);
X=X^(X>>14);
ui W=X^(Y^Z);
X=Y;
Y=Z;
Z=W;
return Z;
}
void updateone(int root,int s1,int e1,int l,int r,int val) //維護區間最小值
{
if(e1<l||s1>r) return;
if(s1>e1)return;
if(Btree[root]>val) return;
if(s1==e1)
{
Btree[root]=val;
a[s1]=val;
return;
}
//pushDown(root);
int mid=(s1+e1)>>1;
if(l<=mid)
updateone(root<<1,s1,mid,l,r,val);
if(mid+1<=r)
updateone((root<<1)|1,mid+1,e1,l,r,val);
Btree[root]=min(Btree[lch],Btree[rch]);
//push_up(root);
}
int main()
{
int t;
int kk=1<<30;
scanf("%d",&t);
while(t--)
{
ll n,m;
scanf("%lld%lld%u%u%u",&n,&m,&X,&Y,&Z);
for(int i=0;i<=n;i++) a[i]=0;
memset(Btree,0,sizeof(Btree));
for(int i=1;i<=3*m;i++)
{
f[i]=RNG61();
}
for(int i=1;i<=m;i++)
{
int l=min((f[3*i-2]%n)+1,(f[3*i-1]%n)+1);
int r=max((f[3*i-2]%n)+1,(f[3*i-1]%n)+1);
int v=f[3*i]%kk;
updateone(1,1,n,l,r,v);
}
ll ans=0;
for(ll i=1;i<=n;i++)
{
ans=ans^(i*a[i]);
}
printf("%lld\n",ans);
}
}