ACM-ICPC 2018 瀋陽賽區網絡預賽 J. Ka Chang

ACM-ICPC 2018 瀋陽賽區網絡預賽 J. Ka Chang
題意:兩個操作,1操作將深度爲x的所有點加權值k,2操作詢問x的子樹的權值和。
q<=1e5,n<=1e5。
思路:可以考慮兩種思路,第一種用樹狀數組維護每個dfs序對應點的權值,當操作1輸入x,k時則把深度爲x的所有點的所對應dfs序再在樹狀數組中都加k,然後查詢子樹x的權值和時即ask(out[x])-ask(in[x]-1),時間複雜度爲o(q * n * log(n))。
第二種開一個向量w[deep]存深度爲deep的點的dfs序,然後當操作1時直接開一個數組sum[deep]代表深度爲deep的點的權值,然後對於每個操作2,對於所有深度都進行一次二分,因爲向量存dfs序時是有序的,所以可以二分找在[in[x],out[x]]這個範圍的深度爲deep的點的個數,然後乘以sum[deep]再累加即可,時間複雜度爲o(q * n * log(n))。
這兩個方法一個操作1是o(1),一個操作2是o(1),但是總的複雜度超時,於是可以分塊,假設深度爲deep的點的個數小於t的化就用第一種方法,時間複雜度爲o(q * t * log(n)),大於等於t用第二種方法,由於點的個數大於等於t的的深度最多爲n/t,所以時間複雜度爲
o(q * (n/t) * log(n))。然後當t=sqrt(n)時綜合時間複雜度最小,爲o(q * log(n) * sqrt(n))。
極限時間複雜度大約爲1e8。
這個時間複雜度將n優化成了根號n,雖然極限數據會T,但是可能因爲很難造出這種極限數據或者根本沒有這種極限數據所以A了,或者1e8也能跑。

#include<iostream>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;
const int MAX_N=101000;
vector<int>v[MAX_N];
vector<int>w[MAX_N],sw[MAX_N];
bool vis[MAX_N];
int in[MAX_N],out[MAX_N];
int cnt=0;
void dfs(int x,int deep){
 vis[x]=true;
 in[x]=++cnt;
 w[deep].push_back(x);
 sw[deep].push_back(cnt);
 for(int i=0;i<v[x].size();i++){
  int y=v[x][i];
  if(vis[y])
  continue;
  dfs(y,deep+1);
 }
 out[x]=cnt;
 //cout<<x<<" "<<in[x]<<" "<<out[x]<<" !!!\n";
}
int n,num[MAX_N];
long long a[MAX_N],sum[MAX_N];
void add(int p,long long x){
 while(p<=n){
  a[p]+=x;
  p+=p&-p;
 }
}
long long ask(int p){
 long long ans=0;
 while(p){
  ans+=a[p];
  p-=p&-p;
 }
 return ans;
} 
int main(void){
 int q,i,j,x,y,op;
 scanf("%d%d",&n,&q);
 for(i=1;i<n;i++){
  scanf("%d%d",&x,&y);
  v[x].push_back(y);
  v[y].push_back(x);
 }
 dfs(1,0);
 int tot=0;
 int nn=sqrt(n);
 for(i=0;i<=n;i++){
  if(w[i].size()>=nn)
  num[++tot]=i;
 }
 long long k;
 //cout<<nn<<" nn\n";
 for(i=0;i<q;i++){
  scanf("%d",&op);
  if(op==1){
   scanf("%d%lld",&x,&k);
   if(w[x].size()<nn){
    for(j=0;j<w[x].size();j++){
     add(in[w[x][j]],k);
    }
   }
   else{
    sum[x]+=k;
   }
  }
  else{
   scanf("%d",&x);
   long long res=ask(out[x])-ask(in[x]-1);
   for(j=1;j<=tot;j++){
    y=num[j];
    res+=sum[y]*(long long)(upper_bound(sw[y].begin(),sw[y].end(),out[x])-lower_bound(sw[y].begin(),sw[y].end(),in[x]));
   }
   printf("%lld\n",res);
  }
 }
 return 0;
}
發佈了62 篇原創文章 · 獲贊 6 · 訪問量 1941
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章