日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[NOIP2018模拟赛10.19]只会暴力报告

發布時間:2025/4/9 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [NOIP2018模拟赛10.19]只会暴力报告 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

閑扯

今天又是暴力滿滿(并不)的一天呢

昨天老師說了分數要正態分布,今天看起來...不過暴力分很多,雖然我人太傻逼又沒打滿

T1 woc?不是說送分的嗎,看起來又是個樹形DP神題,暴力告辭,鏈上的搞一搞

T2 woc?又是樹 紀中這么喜歡出圖/樹題的嗎?第一眼暴力dij告辭

T3 woc?又又又是樹?!看起來十分碼農?!部分分還好很多,想到昨天老師提到了天天愛跑步的例子,感覺可以搞一搞...于是就開始爆肝了...結果期望30分開了個fread爆0了

\(30+30+0\)涼涼,T2堆改成\(paring\)_\(heap\)就50了,辣雞STL.雖然有一個更優的暴力...

T1 lkf

又是道神奇樹形DP,分析先咕會

懶得寫了,看代碼注釋吧...

這道題好題啊

學會兩個技巧

  • 對于差值恰為\(k\)的毒瘤限制,轉化為小于等于\(k\)的限制,答案就是小于等于k的減去小于等于k-1的

  • 對于可能重復計算的狀態強制安排一個順序,如dfs序之類的防止算重

/*code by RyeCatcher */ inline char gc(){static char buf[SIZE],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,SIZE,stdin),p1==p2)?EOF:*p1++; } #define gc getchar template <class T>inline void read(T &x){x=0;int ne=0;char c;while((c=gc())>'9'||c<'0')ne=c=='-';x=c-48;while((c=gc())>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48;x=ne?-x:x;return ; } const int maxn=3335; const int inf=0x7fffffff; const int P=19260817; struct Edge{int ne,to; }edge[maxn<<1]; int h[maxn],num_edge=1; inline void add_edge(int f,int to){edge[++num_edge].ne=h[f];edge[num_edge].to=to;h[f]=num_edge; } int n,k,w[maxn],mx=-inf; int id,o,lim; ll f[maxn][maxn]; ll ans=0; void dfs(int now,int fa){int v;ll p=1;//printf("%d %d\n",now,fa);for(ri i=h[now];i;i=edge[i].ne){v=edge[i].to;if(v==fa)continue;if(w[v]>=o&&w[v]<=o+lim&&(w[v]!=o||(w[v]==o&&v>id))){//前兩個限制是因為狀態的設計本身,第三個限制是防止聯通塊算重,如果還有一個點值為枚舉的最小值,我們可能已經計算了那個聯通塊的個數//于是我們強制安排一個順序使得不重不漏dfs(v,now);p=p*(f[v][lim]+1)%P;//乘法原理,連上v貢獻為f[v][lim] 否則為1}}f[now][lim]=p;return ; } int main(){int x,y;read(n),read(k);for(ri i=1;i<=n;i++){read(w[i]);}for(ri i=1;i<n;i++){read(x),read(y);add_edge(x,y);add_edge(y,x);}for(ri i=1;i<=n;i++){o=w[i],id=i,lim=k;dfs(i,0);if(k==0){ans=(ans+f[i][k])%P;//f[i][k]表示最小值為i,最大值與最小值之差小于等于k的不同聯通塊}else{lim=k-1;dfs(i,0);ans=(ans+(f[i][k]-f[i][lim])%P+P)%P;//顯然f[i]][k]-f[i][k-1]即為差值剛好為k的聯通塊個數}}printf("%lld\n",ans%P);return 0; }

T2 worry

有個性質就是因為你樹上邊隨便走,你斷掉一條樹邊后你最多走一條非樹邊。\(naiive\)的做法就是枚舉了,有沒有更高明的呢?

我們邊從小到大排序,發現對于邊\((x,y)\),它影響\((x,y)\)路徑上的邊(也就是斷掉路徑上的任何一條邊還可以通過\((x,y)\)聯通),也就是\(x,y\)分別到\(lca(x,y)\)路徑上的

樹鏈剖分

那么鏈剖就可以搞嘍,線段樹維護一個永久標記,如果有標記了也不管(因為邊權從小到大排序)

跑得還挺快

/*code by RyeCatcher */ inline char gc(){static char buf[SIZE],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,SIZE,stdin),p1==p2)?EOF:*p1++; } template <class T>inline void read(T &x){x=0;int ne=0;char c;while((c=gc())>'9'||c<'0')ne=c=='-';x=c-48;while((c=gc())>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48;x=ne?-x:x;return ; } const int maxn=200005; const int inf=0x7fffffff; int n,m; struct Edge{int ne,to;ll dis; }edge[maxn<<1]; int h[maxn],num_edge=1; inline void add_edge(int f,int to,ll c){edge[++num_edge].ne=h[f];edge[num_edge].to=to;edge[num_edge].dis=c;h[f]=num_edge; } pair<int,int> qwq[maxn]; struct Niconiconi{int x,y;ll dis;Niconiconi(){x=y=dis=0;}Niconiconi(int _x,int _y,ll _c){x=_x,y=_y,dis=_c;}bool operator <(const Niconiconi &rhs)const{return dis<rhs.dis;} }con[maxn<<1]; int dep[maxn],fa[maxn],son[maxn],size[maxn],top[maxn],dfn[maxn],rnk[maxn],tot=0; void dfs1(int now){int v;size[now]=1;//printf("%d %d\n",now,fa[now]);for(ri i=h[now];i;i=edge[i].ne){v=edge[i].to;if(v==fa[now])continue;dep[v]=dep[now]+1,fa[v]=now;dfs1(v);size[now]+=size[v];if(!son[now]||size[son[now]]<size[v])son[now]=v;}return ; } void dfs2(int now,int t){int v;top[now]=t,dfn[now]=++tot,rnk[tot]=now;if(!son[now])return ;dfs2(son[now],t);for(ri i=h[now];i;i=edge[i].ne){v=edge[i].to;if(v==fa[now]||v==son[now])continue;dfs2(v,v);}return ; } int tag[maxn<<2],w[maxn]; int L,R,dta; inline void pushdown(int now){if(!tag[now<<1])tag[now<<1]=tag[now];//tag[now<<1|1]=tag[now];if(!tag[now<<1|1])tag[now<<1|1]=tag[now]; } void update(int now,int l,int r){if(tag[now])return ;if(L<=l&&r<=R){tag[now]=dta;return ;}int mid=(l+r)>>1;pushdown(now);if(L<=mid&&!tag[now<<1])update(now<<1,l,mid);if(mid<R&&!tag[now<<1|1])update(now<<1|1,mid+1,r);return ; } void ahaha(int now,int l,int r){if(l==r){if(tag[now])w[rnk[l]]=tag[now];else w[rnk[l]]=-1;return ;}int mid=(l+r)>>1;pushdown(now);ahaha(now<<1,l,mid);ahaha(now<<1|1,mid+1,r);return ; } inline void update_path(int x,int y){while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]])std::swap(x,y);L=dfn[top[x]],R=dfn[x];update(1,1,n);x=fa[top[x]];}if(dep[x]>dep[y])std::swap(x,y);L=dfn[x]+1,R=dfn[y];//printf("--%d %d--\n",rnk[L],rnk[R]);if(L>R)return ;update(1,1,n); } int main(){int x,y;ll z;FO(worry);read(n),read(m);for(ri i=1;i<n;i++){read(x),read(y);add_edge(x,y,0);add_edge(y,x,0);qwq[i]=pair<int,int>(x,y);}for(ri i=1;i<=m;i++){read(x),read(y),read(z);con[i]=Niconiconi(x,y,z);}std::sort(con+1,con+1+m);dep[1]=0,fa[1]=0;dfs1(1);dfs2(1,1);memset(tag,0,sizeof(tag));for(ri i=1;i<=m;i++){x=con[i].x,y=con[i].y,dta=con[i].dis;update_path(x,y);}ahaha(1,1,n);for(ri i=1;i<n;i++){x=qwq[i].first,y=qwq[i].second;if(dep[x]<dep[y])std::swap(x,y);printf("%d\n",w[x]);}return 0; }

并查集

題解是更高明的并查集做法,我還是Too Young Too Simple,只會SB暴力樹剖

每個點指向下一個沒被打標記的點\(nxt[x]\)(以點代邊),顯然這是可傳遞的

這樣的話每次查詢直接往上跳就好了,連LCA都不用求

居然跑到rank1哈哈

/*code by RyeCatcher */ inline char gc(){static char buf[SIZE],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,SIZE,stdin),p1==p2)?EOF:*p1++; } #define gc getchar template <class T>inline void read(T &x){x=0;int ne=0;char c;while((c=gc())>'9'||c<'0')ne=c=='-';x=c-48;while((c=gc())>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48;x=ne?-x:x;return ; } const int maxn=100005; const int inf=0x7fffffff; int n,m; struct Edge{int ne,to; }edge[maxn<<1]; int h[maxn],num_edge=1; inline void add_edge(int f,int to){edge[++num_edge].ne=h[f];edge[num_edge].to=to;h[f]=num_edge; } struct Niconiconi{int x,y,z;bool operator <(const Niconiconi &qwq)const{return z<qwq.z;} }nico[maxn]; int ans[maxn],dep[maxn],fa[maxn],nxt[maxn],fa_id[maxn]; int get(int x){return (nxt[x]==x)?nxt[x]:nxt[x]=get(nxt[x]);} void dfs(int now){int v;for(ri i=h[now];i;i=edge[i].ne){if((v=edge[i].to)==fa[now])continue;fa[v]=now,dep[v]=dep[now]+1,fa_id[v]=i;dfs(v);}return ; } int main(){int x,y,z,p;FO(worry);read(n),read(m);nxt[n]=n;for(ri i=1;i<n;i++){read(x),read(y);add_edge(x,y),add_edge(y,x);nxt[i]=i;}for(ri i=1;i<=m;i++){read(nico[i].x),read(nico[i].y),read(nico[i].z);}std::sort(nico+1,nico+1+m);fa[1]=0,dfs(1);for(ri i=1;i<=m;i++){x=get(nico[i].x),y=get(nico[i].y),z=nico[i].z;while(x!=y){if(dep[x]<dep[y])std::swap(x,y);ans[fa_id[x]]=z;nxt[x]=x=get(fa[x]); }}p=2*n;for(ri i=2;i<p;i+=2){printf("%d\n",ans[i]?ans[i]:(ans[i^1]?ans[i^1]:-1));}return 0; }

轉載于:https://www.cnblogs.com/Rye-Catcher/p/9819789.html

《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

以上是生活随笔為你收集整理的[NOIP2018模拟赛10.19]只会暴力报告的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。