[PKUSC2018]星際穿越
阿新 • • 發佈:2018-06-09
mes 之間 struct con roo 維護 gis log span 最小的\(i=min[x]\),此時\(i\)的覆蓋範圍一定包含了\(x\)。讓\(x\)向\(i\)連邊就得到了一個樹形結構。在樹上每個結點建立主席樹維護原圖每個點到樹上對應結點的距離。
。
[PKUSC2018]星際穿越
題目大意:
有一排編號為\(1\sim n\)的\(n(n\le3\times10^5)\)個點,第\(i(i\ge 2)\)個點與\([l_i,i-1]\)之間所有點有雙向邊。\(q(q\le3\times10^5)\)次詢問,每次對於\(l_i,r_i,x_i\),求\(\frac{\sum_{y=l_i}^{r_i}dist(x_i,y)}{r_i-l_i+1}\)。
思路:
首先可以得到一個基本結論,從\(x_i\)出發到\(y\)的最短路中,一定存在至少一種滿足路徑上有且僅有第一步是向右走的。那麽我們不妨對於每一個點\(x\),求出\(x\)右側\(l_i\)
詢問時對於\(l_i,r_i,x_i\),若區間\([l_i,r_i]\)內的結點都與\(x_i\)有連邊,則答案就是\(r_i-l_i+1\)。否則那些在\(x_i\)連邊範圍外的那些點到\(x_i\)的距離,就是主席樹上到\(min[x_i]\)的距離\(+1\)。到\(min[x_i]\)的距離可以主席樹上詢問,剩下的\(+1\)一並計算到\(r_i-l_i+1\)中即可。
時間復雜度\(\mathcal O(n\log n)\)
源代碼:
#include<cstdio>
#include<cctype>
#include<algorithm>
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
const int N=3e5 +1,SIZE=N*30;
int left[N],min[N],par[N];
class SegmentTree {
private:
struct Node {
int left,right,tag,sum;
};
Node node[SIZE];
int sz,new_node(const int &p) {
node[++sz]=node[p];
return sz;
}
public:
int root[N];
void modify(int &p,const int &b,const int &e,const int &l,const int &r) {
p=new_node(p);
if(b==l&&e==r) {
node[p].tag++;
return;
}
node[p].sum+=r-l+1;
const int mid=(b+e)>>1;
if(l<=mid) modify(node[p].left,b,mid,l,std::min(mid,r));
if(r>mid) modify(node[p].right,mid+1,e,std::max(mid+1,l),r);
}
int query(const int &p,const int &b,const int &e,const int &l,const int &r) {
if(!p) return 0;
int ans=node[p].tag*(r-l+1);
if(b==l&&e==r) return ans+node[p].sum;
const int mid=(b+e)>>1;
if(l<=mid) ans+=query(node[p].left,b,mid,l,std::min(mid,r));
if(r>mid) ans+=query(node[p].right,mid+1,e,std::max(mid+1,l),r);
return ans;
}
};
SegmentTree t;
int gcd(const int &a,const int &b) {
return b?gcd(b,a%b):a;
}
int main() {
const int n=getint();
for(register int i=2;i<=n;i++) left[i]=getint();
min[par[n]=n]=left[n];
for(register int i=n-1;i;i--) {
min[i]=std::min(min[i+1],left[i]);
par[i]=par[min[i]]?:i;
}
for(register int i=2;i<=n;i++) {
if(par[i]==i) t.modify(t.root[i]=t.root[min[i]],1,n,1,i-1);
}
for(register int i=2;i<=n;i++) {
t.root[i]=t.root[i]?:t.root[par[i]];
}
for(register int q=getint();q;q--) {
const int l=getint(),r=getint(),x=getint();
int ans=r-l+1;
if(l<left[x]) ans+=t.query(t.root[left[x]],1,n,l,std::min(r,left[x]-1));
const int d=gcd(ans,r-l+1);
printf("%d/%d\n",ans/d,(r-l+1)/d);
}
return 0;
}
[PKUSC2018]星際穿越