感觉这种要么就是二分答案网络流,要么就是最小生成树,(随便口胡的),树德保留节目了属于是。
简简单单一眼最小生成树(又是),边权就是两个点之间存在公共区域的时间,这个距离随便找一找规律就好算了。这里直接给结论了 然后建所有可能的边,最后再最小生成树就行,(听说二分也能做?
点击查看代码
| #include<iostream> |
| #include<cstdio> |
| #include<algorithm> |
| #include<cmath> |
| #define int long long |
| using namespace std; |
| const int maxn=100; |
| inline int read() |
| { |
| int x=0,f=1; |
| char c=getchar(); |
| while(c<'0'||c>'9') |
| { |
| if(c=='-')f=-1; |
| c=getchar(); |
| } |
| while('0'<=c&&c<='9') |
| { |
| x=(x<<1)+(x<<3)+(c^48); |
| c=getchar(); |
| } |
| return x*f; |
| } |
| int n; |
| int abs1(int x){return x>0?x:-x;} |
| int calc(int x1,int y1,int x2,int y2){return ceil((1.0*abs1(x1-x2)+1.0*abs1(y1-y2))/2);} |
| int x[maxn],y[maxn]; |
| struct Edge{int u,v,w;}E[5000];int tote=0; |
| bool cmp(Edge a,Edge b){return a.w<b.w;} |
| int f[100];int find(int x){return x==f[x]?x:f[x]=find(f[x]);} |
| signed main() |
| { |
| n=read(); |
| for(int i=1;i<=n;i++)x[i]=read(),y[i]=read(),f[i]=i;; |
| for(int i=1;i<=n;i++) |
| for(int j=i+1;j<=n;j++) |
| E[++tote].u=i,E[tote].v=j,E[tote].w=calc(x[i],y[i],x[j],y[j]); |
| sort(E+1,E+tote+1,cmp); |
| int cnt=0;int ans=-1; |
| for(int i=1;i<=tote;i++) |
| { |
| if(cnt==n-1)break; |
| int x=find(E[i].u),y=find(E[i].v); |
| if(x==y)continue; |
| f[x]=y; |
| ans=max(ans,E[i].w); |
| } |
| printf("%lld",ans); |
| return 0; |
| } |
:求出基本信息:深度、父亲、子树大小、重儿子编号
:求出序、对应节点的权值、当前节点的重链顶端节点
:求出从到的路径上面的信息
实现方法就是只要当前两个节点的顶端节点不同,就让顶端节点深度更深的点跳到它所在重链的顶端,并且统计这一条链的答案,直到在一条重链上面。最后再把深度深的点跳到浅的点上,再统计这一小节的答案。
画个图就很轻易地知道这时候每个子树的序是一定连续的,所以就可以用线段树来维护区间最值
点击查看代码
| #include<iostream> |
| #include<cstdio> |
| #include<algorithm> |
| #define int long long |
| #define MAXN 200000 |
| using namespace std; |
| inline int read() |
| { |
| long long s=0,w=1; |
| char ch=getchar(); |
| while(ch<'0'||ch>'9') |
| { |
| if(ch=='-')w=-1; |
| ch=getchar(); |
| } |
| while(ch>='0'&&ch<='9') |
| { |
| s=(s<<3)+(s<<1)+(ch^48); |
| ch=getchar(); |
| } |
| return s*w; |
| } |
| template <typename T>void wr(T x) |
| { |
| if(x<0) putchar('-'),x=-x; |
| if(x>9) wr(x/10); |
| putchar(x%10^'0'); |
| return; |
| } |
| int n,m; |
| long long val[MAXN]; |
| struct Edge{int u,v;int nex;}tr[4*MAXN]; |
| int head[MAXN],tote; |
| void add(int u,int v) |
| { |
| tr[++tote].u=u; |
| tr[tote].v=v; |
| tr[tote].nex=head[u]; |
| head[u]=tote; |
| tr[++tote].u=v; |
| tr[tote].v=u; |
| tr[tote].nex=head[v]; |
| head[v]=tote; |
| } |
| int fa[MAXN],siz[MAXN],dep[MAXN],son[MAXN]; |
| void dfs1(int x,int f) |
| { |
| dep[x]=dep[f]+1;siz[x]=1;fa[x]=f; |
| int maxsonsize=-1; |
| for(int i=head[x];i;i=tr[i].nex) |
| { |
| int v=tr[i].v; |
| if(v==f)continue; |
| dfs1(v,x); |
| siz[x]+=siz[v]; |
| if(siz[v]>maxsonsize)maxsonsize=siz[v],son[x]=v; |
| } |
| } |
| int id[MAXN],num;long long w[MAXN];int top[MAXN]; |
| void dfs2(int x,int TOP) |
| { |
| top[x]=TOP;id[x]=++num;w[id[x]]=val[x]; |
| if(!son[x])return; |
| dfs2(son[x],TOP); |
| for(int i=head[x];i;i=tr[i].nex) |
| { |
| int v=tr[i].v; |
| if(v==fa[x]||v==son[x])continue; |
| dfs2(v,v); |
| } |
| } |
| struct Node{int l,r;long long val;long long tag;long long Max;}a[4*MAXN]; |
| long long calc(int x){return a[x].val+(a[x].r-a[x].l+1)*a[x].tag;} |
| void down(int x) |
| { |
| a[x<<1].tag+=a[x].tag; |
| a[(x<<1)|1].tag+=a[x].tag; |
| a[x].val=calc(x); |
| a[x].tag=0; |
| a[x].Max=max(a[x<<1].Max,a[(x<<1)|1].Max); |
| } |
| void build(int x,int l,int r) |
| { |
| a[x].l=l;a[x].r=r; |
| if(l==r){a[x].val=a[x].Max=w[l];return;} |
| int mid=(l+r)>>1; |
| build(x<<1,l,mid); |
| build((x<<1)|1,mid+1,r); |
| a[x].val=calc(x<<1)+calc((x<<1)|1); |
| a[x].Max=max(a[x<<1].Max,a[(x<<1)|1].Max); |
| } |
| void update(int x,int l,int r,int k) |
| { |
| if(a[x].l>=l&&a[x].r<=r){a[x].tag+=k,a[x].Max=k;return;} |
| down(x); |
| int mid=(a[x].l+a[x].r)>>1; |
| if(mid>=l)update(x<<1,l,r,k); |
| if(mid<r)update((x<<1)|1,l,r,k); |
| a[x].val=calc(x<<1)+calc((x<<1)+1); |
| a[x].Max=max(a[x<<1].Max,a[(x<<1)|1].Max); |
| } |
| void change(int x,int pos,int v) |
| { |
| if(a[x].l==a[x].r){a[x].val=v,a[x].Max=v;return;} |
| int mid=(a[x].l+a[x].r)>>1; |
| if(pos<=mid)change(x<<1,pos,v); |
| else change(x<<1|1,pos,v); |
| a[x].val=calc(x<<1)+calc(x<<1|1); |
| a[x].Max=max(a[x<<1].Max,a[x<<1|1].Max); |
| } |
| long long query(int x,int l,int r) |
| { |
| if(a[x].l>=l&&a[x].r<=r){return calc(x);} |
| down(x); |
| int mid=(a[x].l+a[x].r)>>1; |
| long long ret=0; |
| if(mid>=l)ret+=query(x<<1,l,r); |
| if(mid<r)ret+=query((x<<1)|1,l,r); |
| a[x].val=calc(x<<1)+calc((x<<1)|1); |
| a[x].Max=max(a[x<<1].Max,a[(x<<1)|1].Max); |
| return ret; |
| } |
| int querymax(int x,int l,int r) |
| { |
| if(a[x].l>=l&&a[x].r<=r){return a[x].Max;} |
| down(x); |
| int mid=(a[x].l+a[x].r)>>1;int ans=-2147483640; |
| if(mid>=l)ans=max(querymax(x<<1,l,r),ans); |
| if(mid<r)ans=max(querymax((x<<1)|1,l,r),ans); |
| return ans; |
| } |
| long long query_rootsum(int l,int r) |
| { |
| long long ret=0; |
| while(top[l]!=top[r]) |
| { |
| if(dep[top[l]]<dep[top[r]])swap(l,r); |
| ret+=query(1,id[top[l]],id[l]); |
| l=fa[top[l]]; |
| } |
| if(dep[l]>dep[r])swap(l,r); |
| ret+=query(1,id[l],id[r]); |
| return ret; |
| } |
| long long query_max(int l,int r) |
| { |
| long long ans=-2147483640; |
| while(top[l]!=top[r]) |
| { |
| if(dep[top[l]]<dep[top[r]])swap(l,r); |
| ans=max(querymax(1,id[top[l]],id[l]),ans); |
| l=fa[top[l]]; |
| } |
| if(dep[l]>dep[r])swap(l,r); |
| ans=max(querymax(1,id[l],id[r]),ans); |
| return ans; |
| } |
| string s; |
| signed main(){ |
| n=read(); |
| |
| for(int i=1;i<n;i++) |
| { |
| int u,v; |
| u=read(),v=read(); |
| add(u,v); |
| } |
| for(int i=1;i<=n;++i) val[i]=read(); |
| dfs1(1,0); |
| dfs2(1,1); |
| build(1,1,n); |
| int q=read(); |
| for(int i=1;i<=q;i++) |
| { |
| cin>>s; |
| if(s[0]=='C') |
| { |
| int x; |
| long long y; |
| x=read(),y=read(); |
| change(1,id[x],y); |
| } |
| else if(s=="QMAX") |
| { |
| int x;long long y; |
| x=read(),y=read(); |
| wr(query_max(x,y)); |
| printf("\n"); |
| } |
| else if(s=="QSUM") |
| { |
| int x,y; |
| x=read(),y=read(); |
| wr(query_rootsum(y,x)); |
| printf("\n"); |
| } |
| } |
| return 0; |
| } |
一眼矩阵,可是一开始遇到了一些困难,比如转移矩阵里面必须是常值,但是后面经过一系列推导和转化,还是把感觉很妙的一个解给写出来了,马上就要去跑步了,推导的过程明早重点来写,先贴代码吧
:增加了昨天说的心路历程内容
一开始肯定想到的是直接递推对吧,有递推公式,写出来的矩阵暂且认为是
你会发现一定会有一个变量使得矩阵每次都不同,无法使用快速幂,所以要换思路
考虑到中的系数是阶梯状的,我们可以考虑每次加上,再减去前面相应的部分,最后就可以经过次递推得到,我们定义一个,,可以看出来我们每一次递推都可以固定一位的系数,且容易得到递推公式:.
以下就省略一些了,最后的转移矩阵推出来就是:
这样就全部都是常数了
点击查看代码
| #include<iostream> |
| #include<cstdio> |
| #include<algorithm> |
| #include<cstring> |
| #define int long long |
| using namespace std; |
| const int maxn=1e5; |
| struct Matrix{int n,m,a[10][10];Matrix(){memset(a,0,sizeof a);};}sup[5]; |
| int N,M; |
| Matrix operator *(Matrix a,Matrix b) |
| { |
| Matrix tmp;tmp.n=a.n,tmp.m=b.m; |
| for(int i=1;i<=a.n;i++) |
| for(int j=1;j<=b.m;j++) |
| { |
| int c=0; |
| for(int k=1;k<=a.m;k++) c=(c%M+(a.a[i][k]%M)*(b.a[k][j]%M))%M; |
| tmp.a[i][j]=c; |
| } |
| return tmp; |
| } |
| Matrix base(int x) |
| { |
| Matrix tmp;tmp.n=tmp.m=x; |
| for(int i=1;i<=x;i++)tmp.a[i][i]=1; |
| return tmp; |
| } |
| Matrix Mpower(Matrix a,int b) |
| { |
| Matrix ans=base(a.n); |
| while(b) |
| { |
| if(b&1)ans=ans*a; |
| a=a*a; |
| b>>=1; |
| } |
| return ans; |
| } |
| void pre() |
| { |
| sup[1].m=3,sup[1].n=3; |
| sup[1].a[1][1]=1,sup[1].a[1][2]=1; |
| sup[1].a[2][2]=1,sup[1].a[2][3]=1; |
| sup[1].a[3][2]=1; |
| sup[2].m=sup[2].n=5; |
| sup[2].a[1][1]=1,sup[2].a[1][2]=1,sup[2].a[1][3]=-1; |
| sup[2].a[2][2]=1; |
| sup[2].a[3][3]=1;sup[2].a[3][4]=1; |
| sup[2].a[4][4]=1,sup[2].a[4][5]=1; |
| sup[2].a[5][4]=1; |
| } |
| void print(Matrix a) |
| { |
| for(int i=1;i<=a.n;i++) |
| { |
| for(int j=1;j<=a.m;j++) |
| printf("%lld ",a.a[i][j]); |
| printf("\n"); |
| } |
| } |
| signed main() |
| { |
| scanf("%lld%lld",&N,&M); |
| pre(); |
| Matrix ans1;ans1.n=3,ans1.m=1; |
| ans1.a[1][1]=0,ans1.a[2][1]=1,ans1.a[3][1]=0; |
| ans1=Mpower(sup[1],N)*ans1; |
| Matrix ans2;ans2.n=5,ans2.m=1; |
| ans2.a[1][1]=0,ans2.a[2][1]=ans1.a[1][1],ans2.a[3][1]=0,ans2.a[4][1]=1,ans2.a[5][1]=0; |
| ans2=Mpower(sup[2],N)*ans2; |
| printf("%lld",(ans2.a[1][1]+M)%M); |
| return 0; |
| } |
说实话一开始真的没什么思路的,但是想到了对于当前这个位置统计它前后大于和小于它的是否相等,但实在没有想到用的方式来表示,还可以用查分的方式来维护区间和
点击查看代码
| #include<iostream> |
| #include<cstdio> |
| #include<unordered_map> |
| #define ll long long |
| using namespace std; |
| int ans,wei,n,b,a[110000],tot,sum[110000]; |
| unordered_map<int,int>mp; |
| int main(){ |
| |
| |
| ios::sync_with_stdio(false); |
| cin.tie(0); |
| cout.tie(0); |
| cin>>n>>b; |
| for(register int i=1;i<=n;i++){ |
| cin>>a[i]; |
| if(a[i]==b)wei=i; |
| } |
| int big=0,small=0; |
| for(register int i=wei;i>0;i--){ |
| if(a[i]>b)big++; |
| else{ |
| if(a[i]<b)small++; |
| } |
| int delta=big-small; |
| |
| if(mp.find(delta)==mp.end()){ |
| mp[delta]=++tot; |
| } |
| sum[mp[delta]]++; |
| } |
| big=0; |
| small=0; |
| for(register int i=wei;i<=n;i++){ |
| if(a[i]>b)big++; |
| else{ |
| if(a[i]<b)small++; |
| } |
| int delta=big-small; |
| if(mp.find(-delta)==mp.end())continue; |
| ans+=sum[mp[-delta]]; |
| } |
| cout<<ans; |
| return 0; |
| } |
| |
| |
| |
| |
| |
| |
| |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效