铁轨 清北学堂 线段树
【题目描述】
R 国的铁轨经常会进行重新修建。
R 国是一个细长的国家,一共有 n 个城市排成一排,首都位于 1 号城市,相邻两个城市之间有铁路相连。
每次新建铁轨的时候,一定是从首都开始修建,直到某一个城市为止,这其间的铁路都会变成新版本的设
施,而旧设施会被拆除。然而,由于 R 国的工程师脑子不太好使,任意两种不同版本的铁路之间都无法连
接,因此必须要进行换乘。
现在给出你修建铁轨的操作,小 R 时不时第会想问你,如果在第 x 个城市到第 y 个城市之间随机选择一个
城市乘车去往首都,则换乘次数期望是多少次?
初始时所有城市都由同一种铁道设施相连接。【输入格式】
第一行两个整数 n 和 m,代表城市的数量和操作的数量
接下来 m 行,每行代表一个操作
若第一个数为 0,则接下来接一个数 x,代表从 1 号城市到 x 号城市之间的铁路重新修建了。
若第一个数为 1,则接下来接两个数 x 和 y,代表小 R 询问在第 x 个城市到第 y 个城市之间随机选择一个城
市乘车去往首都,换乘的期望次数。【输出格式】
对于每次询问,输出一行一个实数代表答案,保留四位小数
容易想到用线段树维护区间换乘数和来计算期望,对于每次修建,我们将区间\([1,x]\)覆盖为\(0\),对于剩下的区间\([x+1, n]\),我们发现换乘次数改变一定是同步的,于是我们区间减去\(val[x+1]-1\)即可(即将\(x+1\)修改为\(1\))。
注意下放覆盖标记的写法
void push_down(int x, int l, int r){ if(lazy_cover[x]){ tre[sl]=tre[sr]=0; lazy[sl]=lazy[sr]=0; lazy_cover[sl]=lazy_cover[sr]=1; lazy_cover[x]=0; } if(lazy[x]==0) return; int mid=(l+r)>>1; tre[sl]+=lazy[x]*(mid-l+1); lazy[sl]+=lazy[x]; tre[sr]+=lazy[x]*(r-(mid+1)+1); lazy[sr]+=lazy[x]; lazy[x]=0; }
注意精度,JXOJ的数据是用double
跑出来的,所以要用double
)
#include <cstdio> #define MAXN 100010 #define sl (x<<1) #define sr (x<<1|1) using namespace std; inline int read(){ char ch=getchar();int s=0; while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return s; } int tre[MAXN*4]; int lazy[MAXN*4]; bool lazy_cover[MAXN*4]; void push_down(int x, int l, int r){ if(lazy_cover[x]){ tre[sl]=tre[sr]=0; lazy[sl]=lazy[sr]=0; lazy_cover[sl]=lazy_cover[sr]=1; lazy_cover[x]=0; } if(lazy[x]==0) return; int mid=(l+r)>>1; tre[sl]+=lazy[x]*(mid-l+1); lazy[sl]+=lazy[x]; tre[sr]+=lazy[x]*(r-(mid+1)+1); lazy[sr]+=lazy[x]; lazy[x]=0; } void cover(int x, int l, int r, int cl, int cr){ if(cl<=l&&r<=cr){ tre[x]=0; lazy[x]=0; lazy_cover[x]=1; //printf("cover[%d,%d]=%d\n", l, r, tre[x]); return; } push_down(x, l, r); int mid=(l+r)>>1; if(cl<=mid) cover(sl, l, mid, cl, cr); if(mid<cr) cover(sr, mid+1, r, cl, cr); tre[x]=tre[sl]+tre[sr]; //printf("cover[%d,%d]=%d\n", l, r, tre[x]); } void change(int x, int l, int r, int cl, int cr, int val){ if(cl<=l&&r<=cr){ tre[x]+=val*(r-l+1); lazy[x]+=val; return; } push_down(x, l, r); int mid=(l+r)>>1; if(cl<=mid) change(sl, l, mid, cl, cr, val); if(mid<cr) change(sr, mid+1, r, cl, cr, val); tre[x]=tre[sl]+tre[sr]; } int query(int x, int l, int r, int ql, int qr){ if(ql<=l&&r<=qr){ //printf("query[%d,%d]=%d\n", l, r, tre[x]); return tre[x]; } push_down(x, l, r); int mid=(l+r)>>1; int res=0; if(ql<=mid) res+=query(sl, l, mid, ql, qr); if(mid<qr) res+=query(sr, mid+1, r, ql, qr); //printf("query[%d,%d]=%d\n", l, r, res); return res; } inline void myswap(int &a, int &b){ int t=a; a=b; b=t; } int n,m; int s[MAXN],top; int main(){ scanf("%d %d", &n, &m); while(m--){ int opt,x,y; scanf("%d", &opt); if(opt==0){ scanf("%d", &x); cover(1, 1, n, 1, x); change(1, 1, n, x+1, n, 1-query(1, 1, n, x+1, x+1)); }else{ scanf("%d %d", &x, &y); if(x>y) myswap(x, y); printf("%.4lf\n", (double)query(1, 1, n, x, y)*1.0/(y-x+1)); } } return 0; }