noip模擬34(待補)
阿新 • • 發佈:2021-08-09
A.Merchant
B.Equation
一道簡單的線段樹,考場上因為忘了給子樹傳遞資訊掛沒了..
B_code
#include<bits/stdc++.h> using namespace std; namespace BSS { #define p() puts("") #define ll long long int #define ull unsigend ll #define re register ll #define lf double #define mp(x,y) make_pair(x,y) #define lb lower_bound #define ub upper_bound #define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout) #define Fill(x,y) memset(x,y,sizeof x) #define Copy(x,y) memset(x,y,sizeof x) inline ll read() { ll ss=0; bool cit=1; char ch; while(!isdigit(ch=getchar())) if(ch=='-') cit=0; while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar(); return cit?ss:-ss; } } using namespace BSS; const ll N=1e6+51; const lf eps=1e-10; ll m,n,ts,cnt; ll w[N],head[N],dep[N],dfn[N],rk[N],siz[N],b[N]; lf a[15][15]; struct I { ll u,v,nxt; } e[N<<1|1]; struct II { ll lazy,sum; } tr[N*8]; inline void add(ll u,ll v){ e[++ts].u=u; e[ts].v=v; e[ts].nxt=head[u]; head[u]=ts; } inline void spread(ll x,ll l,ll r){ if(tr[x].lazy){ tr[x<<1].sum+=tr[x].lazy; tr[x<<1|1].sum+=tr[x].lazy; tr[x<<1].lazy+=tr[x].lazy; tr[x<<1|1].lazy+=tr[x].lazy; tr[x].lazy=0; } return ; } ll query(ll x,ll l,ll r,ll pos){ if(l==r) return tr[x].sum; ll mid=(l+r)>>1; spread(x,l,r); if(pos<=mid) return query(x<<1,l,mid,pos); else return query(x<<1|1,mid+1,r,pos); } void update(ll x,ll l,ll r,ll ql,ll qr,ll val){ if(l>=ql and r<=qr) { tr[x].sum+=val; tr[x].lazy+=val; return ; } ll mid=(l+r)>>1; spread(x,l,r); if(ql<=mid) update(x<<1,l,mid,ql,qr,val); if(qr>=mid+1) update(x<<1|1,mid+1,r,ql,qr,val); return ; } void dfs(ll now,ll val,ll depth){ dfn[now]=++cnt; rk[cnt]=now; siz[now]=1; if(depth&1) b[now]=val-w[now]; // 奇數 為 -1 else b[now]=val+w[now]; dep[now]=depth; for(re i=head[now];i;i=e[i].nxt){ dfs(e[i].v,b[now],depth+1); siz[now]+=siz[e[i].v]; } return ; } void Guass(ll u,ll v,ll temp){ if(u>v) swap(u,v); a[1][1]=1.0,a[1][2]=1.0,a[1][3]=temp*1.0; b[u]=query(1,1,n,dfn[u]); b[v]=query(1,1,n,dfn[v]); if(dep[u]&1) a[2][1]=-1.0; else a[2][1]=1.0; if(dep[v]&1) a[2][2]=1.0; else a[2][2]=-1.0; a[2][3]=(b[u]-b[v])*1.0; /* for(re i=1;i<=2;i++){ for(re j=1;j<=3;j++) printf("%.2lf ",a[i][j]); puts(""); }puts(""); */ if(a[1][1]==a[2][1] and a[1][2]==a[2][2] and a[1][3]==a[2][3]){ puts("inf"); return ; } if(a[1][1]==a[2][1] and a[1][2]==a[2][2] and a[1][3]!=a[2][3]){ puts("none"); return ; } if(a[1][1]==-a[2][1] and a[1][2]==-a[2][2] and a[1][3]==-a[2][3]){ puts("inf"); return ; } if(a[1][1]==-a[2][1] and a[1][2]==-a[2][2] and a[1][3]!=-a[2][3]){ puts("none"); return ; } a[2][2]-=a[2][1]*a[1][2]; a[2][3]-=a[2][1]*a[1][3]; lf res=a[2][3]/a[2][2]; if(dep[v]&1) res+=b[v]; else res=b[v]-res; temp=(ll)res; if(res!=(ll)res) puts("none"); else printf("%lld\n",temp); return ; } signed main(){ n=read(); m=read(); ll u,v,opt,temp; for(re i=2;i<=n;i++){ v=read(),w[i]=read(); add(v,i); // add(i,v); } dfs(1,0,1); for(re i=1;i<=n;i++){ update(1,1,cnt,dfn[i],dfn[i],b[i]); } for(re i=1;i<=m;i++){ opt=read(); if(opt&1){ u=read(),v=read(); Guass(u,v,read()); } else{ u=read(); if(dep[u]&1){ update(1,1,cnt,dfn[u],dfn[u]+siz[u]-1,w[u]); w[u]=read(); update(1,1,cnt,dfn[u],dfn[u]+siz[u]-1,-w[u]); } else{ update(1,1,cnt,dfn[u],dfn[u]+siz[u]-1,-w[u]); w[u]=read(); update(1,1,cnt,dfn[u],dfn[u]+siz[u]-1,w[u]); } } } return 0; }
C.Rectangle
考場上想了很多:
- 考慮每個方塊造成的貢獻,但是轉移複雜度過於巨大,且思維量和碼量都很巨大,甚至還要使用容斥,於是果斷放棄..
- 使用\(O(n^4)\)列舉每個矩形,然後在此基礎上優化,使用線段樹進行統計,但是並不知道如何才能使用資料結構節約複雜度..
正解是使用列舉左右兩個邊界:
我們從右往左列舉左邊界,然後從左邊界向右列舉右邊界..
之所以這麼做,是因為中間列舉到的點會對將來的統計造成貢獻,因為也會被當作邊界處理..
然後我們就得到了左邊界\(L\)和右邊界\(R\)..
於是答案即為\((R-L)*\Sigma_h\)..
考慮如何求出\(\Sigma_h\)
我們選擇使用樹狀陣列,維護\(sum\)和\(size\)即可..線段樹常數較大,且許多\(log(M)\)皆為滿,故適用樹狀陣列..
我們從下往上分別統計矩形的上下邊界,每統計完一段區間的答案,然後移動右邊界,並使右邊界的點都依附到左邊界即可..