GDOI2016 機密網路

2021-07-11 19:55:19 字數 3895 閱讀 5194

乙個

n 個點的環套樹,每個點有點權

e。詢問所有距離不大於

k 的且滿足(a

的點對(a,

b)的個數,以及點對點權乘積和。1≤

n≤105

,k≤n

,ei≤

104

我比賽時想到的就是這種方法。

我們刪除環上一條邊,將其變成一棵樹,做點分治。如果不考慮刪除的邊的影響,這就是一道點剖經典題(樓天城:《樹中點對個數》),弄出到分治中心的距離,排序後統計即可。但是我們在這裡還需要考慮這條邊的影響。我的方法是對樓天城那題的擴充套件,所以很多東西我都省用原本的演算法,省略介紹。

可以列出:答案=刪邊後滿足要求點對個數-刪邊前後都滿足要求點對個數+刪邊前滿足要求點對個數。

第乙個在點分治中直接計算即可。

處理後兩個時,判重是個很棘手的問題,我是採用以下方法。令刪除的邊為(p

1,p2

) ,我們將所有點分成兩個集合,

a 集滿足∀x

∈a,d

ist(

x,p1

)st(x

,p2)

。類似的,

b 集滿足∀x

∈b,d

ist(

x,p2

)st(x

,p1)

。先思考乙個問題,如果有乙個點對(x

,y) 刪邊後不符合要求,但是刪邊之前符合要求,那麼

x 與

y一定不在同乙個集合。(那些di

st(x

,p1)

=dis

t(x,

p2) 的,肯定不滿足條件,因此不分入集合中)。

那麼第二個東西的計算,我們可以在點剖中順便進行,對於排好序的點,我們使用樹狀陣列維護當前有多少

b 集合的點滿足di

st(x

,p2)

≤i,以及它們的點權和。然後當原本的指標屬於

a 集合時就在樹狀陣列裡統計答案。這樣我們就可以順便算出第二個部分的答案。

第三個部分就很簡單了,直接將所有

b集合點扔進樹狀陣列中,列舉

a 集合點統計即可。

時間複雜度o(

nlog

22n)

。我排序打的是桶排,但還是在oj上1036ms輾過去。

其實這題直接將整個環去掉會更加簡便。

對每棵子樹點剖,然後再加上環,使用樹狀陣列在環上統計即可。

具體實現請讀者自行思考。

時間複雜度o(

nlog

2n) 。

吐槽:模仿st

l 的so

rt,第一次用指標打的桶排。

#include 

#include

#include

#include

#include

using namespace std;

typedef long long ll;

intread()

while (isdigit(ch))

return

x*f;

}const int n=100500;

const int el=n<<1;

const int lgel=18;

const int m=n<<1;

int size[n],fa[n],last[n],t[2][n],da[n],db[n],a[n],h[n],pos[n],d[n];

int n,k,tot,e1,e2,p1,p2,el,lgel;

int tov[m],next[m],rev[m];

int rmq[el][lgel];

int euler[el];

bool vis[n];

ll cnt,ans;

int getrmq(int l,int r)

int lca(int

x,int

y)int dist(int

x,int

y)bool find(int

x,int e)

else

if (rev[e]!=i)

return e1=i,e2=rev[i],p1=tov[e2],p2=tov[e1];

i=next[i];

}return false;

}void dfs(intx)}

void pre()

int que[n],head,tail;

int core(int rt)

}for (head=tail;head;head--)

size[fa[que[head]]]+=size[que[head]];

int mi=n,ret,tmp;

for (head=1;head<=tail;head++)

tmp=max(tmp,size[rt]-size[x]);

if (tmpx,mi=tmp;

}return ret;

}int q1[n],q2[n];

bool cmp(int

x,int

y)int lowbit(int

x)void add(int

x,int

y,ll edit)

}ll query(int

x,int

y) return ret;

}int sss[n],num[n];

void sort(int

*st,int

*en,int mxl)

void calc(int

x) }

sort(q2+1,q2+1+q2[0],mx0);

int sum=0;

for (int i=1;i<=q2[0];i++)

int cur=q2[0];

for (int i=1;i<=q2[0];i++)

tcnt-=cur;

tans-=1ll*a[q2[i]]*sum;

if (cur&&da[q2[i]]0,k-1-da[q2[i]]);

ans+=a[q2[i]]*1ll

*query(1,k-1-da[q2[i]]);}}

while (cur)

}i0=next[i0];

}sort(q1+1,q1+1+q1[0],mx);

int sum=0;

for (int i=1;i<=q1[0];i++)

int cur=q1[0];

for (int i=1;i<=q1[0];i++)

tcnt+=cur;

tans+=1ll*a[q1[i]]*sum;

if (cur&&da[q1[i]]0,k-1-da[q1[i]]);

ans-=a[q1[i]]*1ll

*query(1,k-1-da[q1[i]]);}}

while (cur)

tcnt--,tans-=a[c]*1ll

*a[c];

cnt+=tcnt/2,ans+=tans/2;

vis[c]=true,i=last[c];

while (i)

}void solve()

void insert(int

x,int

y)int main()

for (int i=1;i<=n;i++) a[i]=read();

find(1,0),h[1]=1,dfs(1),pre();

memset(vis,0,sizeof vis),calc(1),solve();

printf("%lld

%lld\n",cnt,ans);

fclose(stdin);

fclose(stdout);

return

0;}

GDOI2016模擬8 8旋轉

alice和bob發明了乙個新的旋轉遊戲。首先,bob給定n個數組成的序列,並把該序列平均分配成若干個塊,每塊正好包含k個數 k能整除n 第一塊由第1到第k個數構成,第二塊由第k 1個數到第2k個數構成,以此類推。接著,bob要求alice對這個序列進行一系列操作,操作有以下兩種 1.把每塊裡面的數...

GDOI2016模擬8 13總結

這次考差了。但事後想了一下,感覺收穫好大。匯報做題情況 當然,裡面不包含收穫 第一題 我的暴力爆零了,原因又是爆int 做題過程中我想到了與眾不同的演算法,一般人會化簡不等式變成斜率優化做,但由於我對斜率優化不大敏感,而且一般斜率優化的題目都是用凸包 叉積來做,這題我也同樣想著用凸包做,但打完發現有...

GDOI2016模擬8 16幫派

農場裡的生活很艱苦,而且當生活很艱苦,你必須堅強起來。奶牛們形成了編號為1到m的幫派。這些幫派一開始和睦相處了一段時間,但是現在失控了!奶牛們在競爭一片大草地的控制權。奶牛之間的衝突發生在連續的若干分鐘內。每一分鐘有乙隻奶牛走進草地。如果此時草地上沒有奶牛,那麼這只新進去的奶牛所在的幫派就能占領這片...