樹狀數組總結篇

來源:互聯網
上載者:User

標籤:下標   數組   friend   main   printf   turn   ...   問題   log   

(本來對於樹狀數組沒啥感覺的....畢竟潛意識的認為只要樹狀數組的能夠解決的問題我都可以用線段樹解決,但是對於一些玄學題目可能會被卡掉T 因為在樹狀數組能適用的題,他在空間和時間都優於線段樹,所以學好樹狀數組也是很重要的,具體的實現過程百度.....實質上只是二進位的運用 熟練運用二進位就能解決相關問題;

傳送門http://poj.org/problem?id=3067

題意:在日本的東海岸和西海岸修交通線,問這些交通線有多少交叉點;

解法:按照x座標升序,相同的情況下y升序排序,然後查詢在之前有多少滿足條件的即可

#include <algorithm>#include <iostream>#include <cstring>#include <cstdio>#define N 1005#define ll long longusing namespace std;typedef struct node{    int x;int y; friend bool operator <(node a,node b){ if(a.x==b.x) return a.y<b.y; else return a.x<b.x; }}node;node a[N*N];ll d[N];int get_id(int x){ return x&(-x);}void update(int x){ while(x<=N){ d[x]++;x+=get_id(x); }}ll Sum(int x){ ll ans=0; while(x>0){ ans+=d[x];x-=get_id(x); } return ans;}int main(){ int T;scanf("%d",&T); int n,m,k;int Case=0; while(T--){ scanf("%d%d%d",&n,&m,&k); int aa,bb; memset(d,0,sizeof(d)); for(int i=1;i<=k;i++){ scanf("%d%d",&a[i].x,&a[i].y); } sort(a+1,a+k+1); update(a[1].y); ll sum=0; for(int i=2;i<=k;i++){ sum+=(i-1-Sum(a[i].y)); update(a[i].y); } printf("Test case %d: ",++Case); printf("%lld\n",sum); } return 0;}

 

傳送門 http://poj.org/problem?id=3321

題意:給你一顆蘋果樹,每個節點初始都有一個蘋果,執行一些操作(有蘋果的直接拿掉 沒有的直接補上去一個蘋果),然後查詢這個節點的子樹上有多少個蘋果;

解法:第一反應樹剖+樹狀數組查詢區間和(似乎有更簡單的樹狀數組 並不會2333333)

#include <iostream>#include <algorithm>#include <queue>#include <vector>#include <cstdio>#include <cstring>#define N 100005using namespace std;int pos;int son[N];int deep[N];int a[N];int first[N*2];int Next[N*2];int vi[N*2];void intx(){ pos=0; deep[0]=0; for(int i=1;i<N;i++) first[i]=-1; for(int i=1;i<N;i++) son[i]=-1;}int fa[N];int num[N];void dfs1(int v,int pre){ fa[v]=pre;num[v]=1;deep[v]=deep[pre]+1; for(int i=first[v];i!=-1;i=Next[i]){ if(vi[i]!=pre){ dfs1(vi[i],v); num[v]+=num[vi[i]]; if(son[v]==-1||num[son[v]]<num[vi[i]]){ son[v]=vi[i]; } } }}int p[N];int tp[N];int fp[N];void dfs2(int v,int td){ p[v]=++pos;fp[p[v]]=v;tp[v]=td; if(son[v]!=-1) dfs2(son[v],td); for(int i=first[v];i!=-1;i=Next[i]){ if(vi[i]!=fa[v]&&vi[i]!=son[v]) dfs2(vi[i],vi[i]); }}int d[N];int get_id(int x){ return x&(-x);}int n;void get_d(int n){ for(int i=1;i<=n;i++){ int j=i; while(j<=n){ d[j]+=a[i];j+=get_id(j); } }}void update(int x,int t){ while(x<=n){ d[x]+=t;x+=get_id(x); }}int Sum(int x){ int ans=0; while(x>0){ ans+=d[x];x-=get_id(x); } return ans;}int main(){ while(scanf("%d",&n)==1){ int aa,bb; intx(); for(int i=1;i<=(n-1)*2;i++){ scanf("%d%d",&aa,&bb); Next[i]=first[aa]; first[aa]=i; vi[i]=bb; i++; Next[i]=first[bb]; first[bb]=i; vi[i]=aa; // vec[aa].push_back(bb);vec[bb].push_back(aa); } dfs1(1,0); dfs2(1,1); memset(a,0,sizeof(a)); for(int i=1;i<=n;i++) a[i]=1; memset(d,0,sizeof(d)); get_d(n); int q;scanf("%d",&q);char s[5]; for(int i=1;i<=q;i++){ scanf("%s",s); if(s[0]==‘Q‘){ scanf("%d",&aa); int t1=p[aa];int t2=p[aa]+num[aa]-1; printf("%d\n",Sum(t2)-Sum(t1-1)); } else if(s[0]==‘C‘){ scanf("%d",&aa); if(a[aa]==0){ a[aa]=1;update(p[aa],1); } else{ a[aa]=0;update(p[aa],-1); } } } // for(int i=1;i<=n;i++) vec[i].clear(); } return 0;}

 

傳送門http://poj.org/problem?id=2481

題意:求一個區間是多少個區間真子區間(只允許一個端點相同)

解法:按照x升序排序後,x相同時按照y的降序排序;然後查詢即可(可能存在完全相等的兩個區間;要注意這個下標從0開始)

#include <iostream>#include <algorithm>#include <cstring>#include <map>#include <vector>#include <cstdio>#define N 100005using namespace std;typedef struct node{ int x;int y;int biao; friend bool operator<(node a,node b){ if(a.x==b.x) return a.y>b.y; return a.x<b.x; }}node;node a[N];int d[N];int vis[N];int get_id(int x){ return x&(-x);}void update(int x){ while(x<=N){ d[x]++;x+=get_id(x); }}void Sum(int x,int biao){ int ans=0; while(x>0){ ans+=d[x]; x-=get_id(x); } vis[biao]=ans;}int main(){ int n; while(scanf("%d",&n)==1&&n){ int xx,yy;node t; memset(vis,0,sizeof(vis)); memset(d,0,sizeof(d)); for(int i=1;i<=n;i++){ scanf("%d%d",&a[i].x,&a[i].y);a[i].x++;a[i].y++;a[i].biao=i; } int u=0; sort(a+1,a+n+1); for(int i=1;i<=n;i++){ if(i==1){ Sum(a[i].y-1,a[i].biao); vis[a[i].biao]=u-vis[a[i].biao]; } else{ if(a[i].x==a[i-1].x&&a[i].y==a[i-1].y) vis[a[i].biao]=vis[a[i-1].biao]; else{ Sum(a[i].y-1,a[i].biao); vis[a[i].biao]=u-vis[a[i].biao]; } } u++; update(a[i].y); } for(int i=1;i<=n;i++){ if(i==1) printf("%d",vis[i]); else printf(" %d",vis[i]); } printf("\n"); } return 0;}

 傳送門http://poj.org/problem?id=2352

題意:給你每個星星的位置,求這個星星的座標範圍內有多少個星星(包括自己)

題解:按照x升序x相同時升序,尋找統計即可;

#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#define N 32005#define M 15005using namespace std;typedef struct node{    int x;int y; friend bool operator<(node a,node b){ if(a.x==b.x) return a.y<b.y; return a.x<b.x; }}node;int n;node a[M];int d[N];int vis[N];int get_id(int x){ return x&(-x);}void update(int x){ while(x<=N){ d[x]++; x+=get_id(x); }}void Sum(int x){ int ans=0; while(x>0){ ans+=d[x]; x-=get_id(x); } vis[ans]++;}int main(){ while(scanf("%d",&n)==1){ int xx;int yy; for(int i=1;i<=n;i++){ scanf("%d%d",&xx,&yy);a[i].x=xx+1;a[i].y=yy+1; } memset(vis,0,sizeof(vis)); memset(d,0,sizeof(d)); sort(a+1,a+n+1); for(int i=1;i<=n;i++){ update(a[i].y); Sum(a[i].y); } for(int i=1;i<=n;i++){ printf("%d\n",vis[i]); } } return 0;}

 

樹狀數組總結篇

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.