乙個
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的幫派。這些幫派一開始和睦相處了一段時間,但是現在失控了!奶牛們在競爭一片大草地的控制權。奶牛之間的衝突發生在連續的若干分鐘內。每一分鐘有乙隻奶牛走進草地。如果此時草地上沒有奶牛,那麼這只新進去的奶牛所在的幫派就能占領這片...