Article directory
subject
thinking
It's very skillful to choose "time" of line tree divide and conquer. We can consider it from two aspects: time and position:
- In addition to the special products of each store, the time dimension is modified as a single point, and the query is an interval
- Location and modification are all single points, and inquiry is interval
It is also possible to divide and conquer with time dimension. Here, select location as the "time" of segment tree divide and conquer
This question has its own characteristics. It's interval query. We will split the query into O(nlogn)O(nlogn)O(nlogn) segments. What about the modification? It's all single point?
You can add all the lognlognlog points on the path to the value for a single modification by using the tag permanence
This ensures that the split nodes in the query [L,R][L,R][L,R] have valid values for self intervals (no matter whether the time is right or not)
Each node of the segment tree is a TrieTrieTrie
If only the exclusive or maximum value of query is 01Trie01Trie01Trie, but there is a time limit [L,R][L,R][L,R]
Consider sorting all operations by the right endpoint (in fact, the input order is already in order) before inserting
Then add maxumax? To the TrieTrieTrie node to indicate the latest insertion time in the subtree, and judge when asking
Code
#include<map> #include<set> #include<stack> #include<queue> #include<cmath> #include<cstring> #include<climits> #include<cstdio> #include<iostream> #include<algorithm> using namespace std; #define LL long long //#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++) //char buf[(1 << 21) + 1], *p1 = buf, *p2 = buf; inline LL read() { bool f=0;LL x=0;char c=getchar(); while(c<'0'||'9'<c){if(c==EOF)exit(0);if(c=='-')f=1;c=getchar();} while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar(); return !f?x:-x; } #define lch (u<<1) #define rch (u<<1|1) #define MAXN 100000 #define INF 0x3f3f3f3f struct node{ int type,tl,tr,pl,pr,val,id; friend bool operator < (node a,node b){return a.tr==b.tr?a.type<b.type:a.tr<b.tr;} }Q[MAXN+5]; int qcnt,ans[MAXN+5]; vector<node> tree[5*MAXN+5]; void Insert_Seg(int u,int L,int R,node p){ if(p.type==0) tree[u].push_back(p); if(p.pl<=L&&R<=p.pr){ if(p.type==1) tree[u].push_back(p); return ; } int Mid=(L+R)>>1; if(p.pl<=Mid) Insert_Seg(lch,L,Mid,p); if(Mid+1<=p.pr) Insert_Seg(rch,Mid+1,R,p); return ; } int ncnt,Root,ch[30*MAXN+5][2],Max[30*MAXN+5]; void Init(){ for(int i=1;i<=ncnt;i++) ch[i][0]=ch[i][1]=Max[i]=0; ncnt=Root=1; return ; } void Insert(int pos,int val){ int u=Root; for(int i=19;i>=0;i--){ int t=(val>>i)&1; if(!ch[u][t]) ch[u][t]=++ncnt; u=ch[u][t]; Max[u]=max(Max[u],pos); } return ; } int Query(int pos,int val){ int u=Root,ret=0; for(int i=19;i>=0;i--){ int t=((val>>i)&1)^1; if(ch[u][t]&&pos<=Max[ch[u][t]]) ret+=(1<<i),u=ch[u][t]; else u=ch[u][t^1]; } return ret; } void DFS(int u,int L,int R){ Init(); for(int i=0;i<(int)tree[u].size();i++){ node p=tree[u][i]; if(p.id==1){ i++; i--; } if(p.type==0) Insert(p.tr,p.val); else ans[p.id]=max(ans[p.id],Query(p.tl,p.val)); } if(L==R) return ; int Mid=(L+R)>>1; DFS(lch,L,Mid),DFS(rch,Mid+1,R); return ; } int main(){ int n=read(),m=read(),day=1,cnt=0; for(int i=1;i<=n;i++) Insert_Seg(1,1,n,(node){0,1,m+1,i,i,read(),0}); for(int i=1;i<=m;i++){ int opt=read(); node p; if(opt==0){ day++; int s=read(),v=read(); p=(node){0,day,day,s,s,v,0}; } else{ int pl=read(),pr=read(),x=read(),tl=day-read()+1,tr=day; p=(node){1,tl,tr,pl,pr,x,++cnt}; } Insert_Seg(1,1,n,p); } DFS(1,1,n); for(int i=1;i<=cnt;i++) printf("%d\n",ans[i]); return 0; }
Reflection
For the segment tree divide and conquer itself can ensure the "time" order, then it is a good way to try to order other parameters after offline sorting