日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

中石油训练赛 - 小A盗墓(线段树+异或结论)

發布時間:2024/4/11 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 中石油训练赛 - 小A盗墓(线段树+异或结论) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目鏈接:點擊查看

題目大意:給出n個數,以及m個操作,每個操作分為兩種:

  • 1 x y:將第x個數變為y
  • 2 x y:判斷閉區間[x,y]中的數能否在進行升序排序后構成一段連續且上升序列
  • 題目分析:因為涉及到了區間修改和區間查詢的問題,所以我們首先想到利用線段樹來輔助解決,第一個操作很簡單,單點修改,主要是我們該怎么樣在規定時間內完成第二個操作才是問題,這個題目的n和m給的都是5e5,那么我們每次查詢最多只能以logn的復雜度查詢,就已經達到2e7的時間復雜度了,線段樹已經占用掉了logn的復雜度,所以留給我們的只能用O(1)的復雜度來判斷這個條件了。我想過能不能用歸并樹來實現這個題,應該不大行,畢竟是已經被淘汰了的數據結構,之前興致勃勃的用歸并樹做主席樹的題,很失望的T掉了555。說回這個題,我們需要知道一個結論,就是從1~n異或出來的結果是有規律的,詳情請看我的上個博客,有了這個就好判斷了,我們可以用線段樹維護一個最小值,一個區間和,一個異或值,判斷的時候,我們可以通過最小值和區間長度判斷出最大值(因為數都是連續的,所以最小值加上區間長度就是最大值了。。),然后首先利用等差數列求和公式求一下這段的區間和應該是多少,再和線段樹中儲存的比較一下,如果相等再接著用異或的那個規律比較一下,這樣就能通過O(1)判斷是否滿足條件了。

    對了有個細節需要注意一下,若求0~n區間異或的函數是xor_n(int n),那么我們想求x~y區間內的異或,應該是xor_n(y)^xor_n(x-1)

    而不是xor_n(y)-xor_n(x-1),想一想,為什么?

    好了直接上代碼了:

    #include<iostream> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=5e5+100;struct Node {int l,r;int mmin,xor_;LL sum; }tree[N<<2];void pushup(int k) {tree[k].mmin=min(tree[k<<1].mmin,tree[k<<1|1].mmin);tree[k].xor_=tree[k<<1].xor_^tree[k<<1|1].xor_;tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum; }void build(int k,int l,int r) {tree[k].l=l;tree[k].r=r;if(l==r){scanf("%d",&tree[k].mmin);tree[k].sum=tree[k].xor_=tree[k].mmin;return;}int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);pushup(k); }void update(int k,int pos,int val) {if(tree[k].l==tree[k].r){tree[k].sum=tree[k].mmin=tree[k].xor_=val;return;}int mid=tree[k].l+tree[k].r>>1;if(mid>=pos)update(k<<1,pos,val);elseupdate(k<<1|1,pos,val);pushup(k); }int querymin(int k,int l,int r) {if(tree[k].r<l||tree[k].l>r)return inf;if(tree[k].r<=r&&tree[k].l>=l)return tree[k].mmin;return min(querymin(k<<1,l,r),querymin(k<<1|1,l,r)); }int queryxor(int k,int l,int r) {if(tree[k].r<l||tree[k].l>r)return 0;if(tree[k].r<=r&&tree[k].l>=l)return tree[k].xor_;return queryxor(k<<1,l,r)^queryxor(k<<1|1,l,r); }LL querysum(int k,int l,int r) {if(tree[k].r<l||tree[k].l>r)return 0;if(tree[k].r<=r&&tree[k].l>=l)return tree[k].sum;return querysum(k<<1,l,r)+querysum(k<<1|1,l,r); }int xor_n(int n) {int temp=n&3;if(temp&1)return temp/2^1;return temp/2^n; }bool check(int len,int mmin,int xor_,LL sum) {int mmax=mmin+len-1;LL ssum=(1LL)*len*mmin+(1LL)*len*(len-1)/2;if(ssum!=sum)return false;int _xor_=xor_n(mmax)^xor_n(mmin-1);if(_xor_!=xor_)return false;return true; }int main() {int n,m;scanf("%d%d",&n,&m);build(1,1,n);while(m--){int op,x,y;scanf("%d%d%d",&op,&x,&y);if(op==1)update(1,x,y);else{int mmin=querymin(1,x,y);int xor_=queryxor(1,x,y);LL sum=querysum(1,x,y);if(check(y-x+1,mmin,xor_,sum))printf("Yes\n");elseprintf("No\n");}}return 0; }

    ?

    總結

    以上是生活随笔為你收集整理的中石油训练赛 - 小A盗墓(线段树+异或结论)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。