9.8<2>题解
T1
考场上以为是线段不能重叠,以至于我推了很久都没有结果,样例不是小的没意义,就是大的手玩不出来,然后我就死了
题解告诉我们他是直线,他用了向量来解释,对于方向向量$(a,b)$,这个方向可以做贡献,一个限制就是$gcd(a,b)=1$,然后就是这个方向有几条直线,如果定义一个点$(x,y)$的前驱为$(x-a,y-b)$,后继为$(x+a,y+b)$,那符合条件的直线的数量就是满足前驱在点阵中,后继不在点阵中的点的数量,然后题解就告诉我说
然而他并没有告诉我经过了什么样的计算,我们来理解一下,前面$(n-a){\times}(m-b)$是所有的前驱在点阵中的点的数量,然后就是刨去后继也在点阵中的点的数量,那其实就是一个点找两个前驱,他的两个前驱都在点阵中的点的数量,那肯定就是$(n-2{\times}a){\times}(m-2{\times}b)$,计算这个东西还是需要$O(n^2)$枚举$a$和$b$,$T$又很大,还是过不去,所以说我们选择前缀和优化他,拆成4个前缀和就可以做了,但是,这个毒瘤出题人他卡空间,然后我就不知道怎么办了,然后就是疯狂${\%}{\%}{\%}{\%}{\%}Smily$,我们发现每个前缀和对答案做贡献都可以是独立的所以,我们用一个前缀和,统计一次答案,清一次,就刚好可以卡过去了。。。。
1 #include<algorithm> 2 #include<iostream> 3 #include<cstdio> 4 #include<cmath> 5 #define maxn 4010 6 #define maxm 10100 7 #define ll long long 8 #define mod 1073741824 9 using namespace std; 10 struct node{ 11 int n,m; 12 ll ans; 13 }q[maxm]; 14 int T,maxxn,maxxm; 15 ll ans,ls; 16 int a[maxn][maxn]; 17 bool g[maxn][maxn]; 18 bool gcd(int x,int y) 19 { 20 if(x%2==0&&y%2==0) return 0; 21 while(1) 22 { 23 if(x==1||y==1) return 1; 24 if(x==0||y==0) return 0; 25 while(x%2==0) x/=2; 26 while(y%2==0) y/=2; 27 if(x<y) swap(x,y); 28 x-=y; 29 } 30 } 31 inline int read() 32 { 33 int e=0; char ch=getchar(); 34 while(ch<'0'||ch>'9') ch=getchar(); 35 while(ch>='0'&&ch<='9') {e=(e<<3)+(e<<1)+(ch^48); ch=getchar();} 36 return e; 37 } 38 int main() 39 { 40 T=read(); 41 for(int i=1;i<=T;++i) 42 { 43 q[i].n=read(); q[i].m=read(); 44 maxxn=max(maxxn,q[i].n); maxxm=max(maxxm,q[i].m); 45 } 46 for(int i=1;i<=maxxn;++i)//t 47 { 48 for(int j=1;j<=maxxm;++j) 49 { 50 if(gcd(i,j)) {a[i][j]=1; g[i][j]=1;} 51 else a[i][j]=0; 52 ls=(a[i-1][j]+a[i][j-1])%mod; 53 ls=(ls-a[i-1][j-1]+mod)%mod; ls=(ls+a[i][j])%mod; a[i][j]=ls; 54 } 55 } 56 for(int o=1;o<=T;++o) 57 { 58 ls=(q[o].n*q[o].m)%mod; ls=(ls*a[q[o].n-1][q[o].m-1])%mod; 59 q[o].ans=(q[o].ans+ls)%mod; 60 int i=q[o].n/2,j=q[o].m/2; 61 ls=(q[o].n*q[o].m)%mod; ls=(ls*a[i][j])%mod; 62 q[o].ans=(q[o].ans-ls+mod)%mod; 63 q[o].ans=((q[o].ans%mod)+mod)%mod; 64 } 65 for(int i=1;i<=maxxn;++i)//b 66 { 67 for(int j=1;j<=maxxm;++j) 68 { 69 if(g[i][j]) a[i][j]=j; 70 else a[i][j]=0; 71 ls=(a[i-1][j]+a[i][j-1])%mod; 72 ls=(ls-a[i-1][j-1]+mod)%mod; ls=(ls+a[i][j])%mod; a[i][j]=ls; 73 } 74 } 75 for(int o=1;o<=T;++o) 76 { 77 ls=(q[o].n*a[q[o].n-1][q[o].m-1])%mod; q[o].ans=(q[o].ans-ls+mod)%mod; 78 int i=q[o].n/2,j=q[o].m/2; 79 ls=(2*q[o].n*a[i][j])%mod; q[o].ans=(q[o].ans+ls)%mod; 80 q[o].ans=((q[o].ans%mod)+mod)%mod; 81 } 82 for(int i=1;i<=maxxn;++i)//a 83 { 84 for(int j=1;j<=maxxm;++j) 85 { 86 if(g[i][j]) a[i][j]=i; 87 else a[i][j]=0; 88 ls=(a[i-1][j]+a[i][j-1])%mod; 89 ls=(ls-a[i-1][j-1]+mod)%mod; ls=(ls+a[i][j])%mod; a[i][j]=ls; 90 } 91 } 92 for(int o=1;o<=T;++o) 93 { 94 ls=(q[o].m*a[q[o].n-1][q[o].m-1])%mod; q[o].ans=(q[o].ans-ls+mod)%mod; 95 int i=q[o].n/2,j=q[o].m/2; 96 ls=(2*q[o].m*a[i][j])%mod; q[o].ans=(q[o].ans+ls)%mod; 97 q[o].ans=((q[o].ans%mod)+mod)%mod; 98 } 99 for(int i=1;i<=maxxn;++i)//ab 100 { 101 for(int j=1;j<=maxxm;++j) 102 { 103 if(g[i][j]) a[i][j]=i*j; 104 else a[i][j]=0; 105 ls=(a[i-1][j]+a[i][j-1])%mod; 106 ls=(ls-a[i-1][j-1]+mod)%mod; ls=(ls+a[i][j])%mod; a[i][j]=ls; 107 } 108 } 109 for(int o=1;o<=T;++o) 110 { 111 ls=a[q[o].n-1][q[o].m-1]; q[o].ans=(q[o].ans+ls)%mod; 112 int i=q[o].n/2,j=q[o].m/2; 113 ls=(4*a[i][j])%mod; q[o].ans=(q[o].ans-ls+mod)%mod; 114 q[o].ans=(q[o].ans*2)%mod; q[o].ans=(q[o].ans+q[o].n+q[o].m)%mod; 115 q[o].ans=((q[o].ans%mod)+mod)%mod; 116 printf("%lld\n",q[o].ans); 117 } 118 return 0; 119 }
T2
这道题有两种解法,一个是点分治,一个是并查集,点分治我显然还没学会,所以就打的并查集的思路
这题的一个难点在于它既要最小点值,又要最大边值和,那我们考虑枚举最小点值,用并查集直接维护边值和,由于我们是枚举的最小点值,所以只需要让边值和最大,那就并查集记录当前并查集中的最长路径长度,以及这个最长路的两个端点,合并并查集的时候几个端点一通乱配就解决了
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 #define maxn 100100 6 #define int long long 7 #define ll long long 8 using namespace std; 9 struct node{ 10 int val,pos; 11 }v[maxn]; 12 struct NODE{ 13 ll len; 14 int po[3]; 15 }bcj[maxn]; 16 int T,n,js; 17 ll ans; 18 int head[maxn],to[maxn*2],xia[maxn*2],w[maxn*2]; 19 int deep[maxn],pd[maxn],f[maxn],ww[maxn],bh[maxn],fa[maxn][21]; 20 ll sum[maxn]; 21 bool cmp(const node &a,const node &b) 22 { 23 return a.val==b.val?a.pos<b.pos:a.val>b.val; 24 } 25 void clear() 26 { 27 js=0; ans=0; 28 memset(head,0,sizeof(head)); memset(pd,0,sizeof(pd)); 29 } 30 void add(int x,int y,int z) 31 { 32 to[++js]=y; xia[js]=head[x]; w[js]=z; head[x]=js; 33 } 34 void dfs(int x) 35 { 36 pd[x]=1; 37 for(int i=head[x];i;i=xia[i]) 38 { 39 int ls=to[i]; 40 if(pd[ls]) continue; 41 deep[ls]=deep[x]+1; fa[ls][0]=x; sum[ls]=sum[x]+w[i]; 42 for(int j=1;j<=20;++j) fa[ls][j]=fa[fa[ls][j-1]][j-1]; 43 dfs(ls); 44 } 45 } 46 int LCA(int x,int y) 47 { 48 if(deep[x]<deep[y]) swap(x,y); 49 for(int i=20;i>=0;--i) 50 if(deep[fa[x][i]]>=deep[y]) x=fa[x][i]; 51 if(x==y) return x; 52 for(int i=20;i>=0;--i) 53 if(fa[x][i]!=fa[y][i]) {x=fa[x][i]; y=fa[y][i];} 54 return fa[x][0]; 55 } 56 int find(int x) 57 { 58 if(f[x]!=x) f[x]=find(f[x]); 59 return f[x]; 60 } 61 void merge(int fa,int son) 62 { 63 int po1=0,po2=0; ll lenn=0; 64 for(int i=1;i<=2;++i) 65 for(int j=1;j<=2;++j) 66 { 67 int lca=LCA(bcj[fa].po[i],bcj[son].po[j]); 68 ll lslen=sum[bcj[fa].po[i]]-sum[lca]+sum[bcj[son].po[j]]-sum[lca]; 69 if(lslen>lenn) {po1=bcj[fa].po[i]; po2=bcj[son].po[j]; lenn=lslen;} 70 } 71 if(lenn>bcj[fa].len) {bcj[fa].len=lenn; bcj[fa].po[1]=po1; bcj[fa].po[2]=po2;} 72 if(bcj[fa].len<bcj[son].len) 73 { 74 bcj[fa].len=bcj[son].len; 75 for(int i=1;i<=2;++i) bcj[fa].po[i]=bcj[son].po[i]; 76 } 77 } 78 main() 79 { 80 //freopen("b.in","r",stdin); 81 scanf("%lld",&T); 82 while(T--) 83 { 84 scanf("%lld",&n); clear(); 85 for(int i=1;i<=n;++i) {scanf("%lld",&v[i].val); v[i].pos=i; ww[i]=v[i].val;} 86 for(int i=1;i<n;++i) 87 { 88 int u,v,w; scanf("%lld%lld%lld",&u,&v,&w); 89 add(u,v,w); add(v,u,w); 90 } 91 deep[1]=1; sum[1]=0; dfs(1); sort(v+1,v+n+1,cmp); 92 for(int i=1;i<=n;++i) 93 { 94 bh[v[i].pos]=i; f[i]=i; 95 bcj[i].po[1]=i; bcj[i].po[2]=i; bcj[i].len=0; 96 } 97 for(int i=1;i<=n;++i) 98 { 99 int now=v[i].pos; 100 for(int j=head[now];j;j=xia[j]) 101 { 102 int ls=to[j]; 103 if(ww[ls]<ww[now]||(ww[ls]==ww[now]&&bh[ls]>i)) continue; 104 int ls1=find(f[now]),ls2=find(f[ls]); 105 f[ls2]=ls1; merge(ls1,ls2); 106 } 107 ans=max(ans,bcj[now].len*v[i].val); 108 } 109 printf("%lld\n",ans); 110 } 111 return 0; 112 }
T3
考试的时候觉得有点像好久好久之前考过的旅馆那道题,但是最终还是没打线段树,本来打了一个优先队列优化,但是因为时间不够,没调出来,我就把几十行的代码删了,打了个暴力,正解还是线段树,考虑维护区间最左边花精,最右边花精,最长的空区间长度,以及最长的空区间长度对应的那个中间的点
对于询问一,直接找1节点对应的答案,也就是$l-1$,$n-r$,$p$先比较长度,长度相同选最靠左的,选过之后把当前位置放上花精,更新线段树
对于询问二,把该位置清空,更新线段树,$update$那一块细节稍多,yy了好久也没yy明白,最后稍颓了一下下代码。。。。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #define maxn 200200 6 #define maxx 1001000 7 #define inf 30000000 8 using namespace std; 9 struct node{ 10 int zuo,you,l,r,mid,p; 11 }a[maxn<<2]; 12 int n,m,opt,num; 13 int pos[maxx]; 14 inline int read() 15 { 16 int e=0; char ch=getchar(); 17 while(ch<'0'||ch>'9') ch=getchar(); 18 while(ch>='0'&&ch<='9') {e=(e<<3)+(e<<1)+(ch^48); ch=getchar();} 19 return e; 20 } 21 void build(int fa,int l,int r) 22 { 23 a[fa].zuo=l; a[fa].you=r; 24 if(l==r) return ; 25 int mid=(l+r)>>1; 26 build(2*fa,l,mid); build(2*fa+1,mid+1,r); 27 } 28 void update(int fa) 29 { 30 if(a[2*fa].l!=0) a[fa].l=a[2*fa].l; 31 else a[fa].l=a[2*fa+1].l; 32 if(a[2*fa+1].r!=0) a[fa].r=a[2*fa+1].r; 33 else a[fa].r=a[2*fa].r; 34 a[fa].mid=a[2*fa].mid; a[fa].p=a[2*fa].p; 35 if(a[2*fa].r!=0&&a[2*fa+1].l!=0) 36 { 37 int len=(a[2*fa+1].l-a[2*fa].r)>>1; 38 if(len>a[fa].mid) {a[fa].mid=len; a[fa].p=(a[2*fa].r+a[2*fa+1].l)>>1;} 39 if(a[2*fa+1].mid>a[fa].mid) {a[fa].mid=a[2*fa+1].mid; a[fa].p=a[2*fa+1].p;} 40 } 41 } 42 void change(int fa,int x,int op) 43 { 44 if(a[fa].zuo==a[fa].you) 45 { 46 if(op==1) {a[fa].l=a[fa].you; a[fa].r=a[fa].zuo;} 47 else {a[fa].l=0; a[fa].r=0;} 48 return ; 49 } 50 int mid=(a[fa].zuo+a[fa].you)>>1; 51 if(x<=mid) change(2*fa,x,op); 52 else change(2*fa+1,x,op); 53 update(fa); 54 } 55 int main() 56 { 57 n=read(); m=read(); 58 build(1,1,n); 59 for(int i=1;i<=m;++i) 60 { 61 opt=read(); num=read(); 62 if(opt==1) 63 { 64 int MA=0,po; 65 if(a[1].l==0) {MA=inf; po=1;} 66 if(a[1].r==0&&MA!=inf) {MA=inf; po=n;} 67 if(a[1].l-1>MA) {MA=a[1].l-1; po=1;} 68 if(a[1].mid>MA) {MA=a[1].mid; po=a[1].p;} 69 if(n-a[1].r>MA) {MA=n-a[1].r; po=n;} 70 pos[num]=po; change(1,po,1); 71 printf("%d\n",pos[num]); 72 } 73 else change(1,pos[num],0); pos[num]=0; 74 } 75 return 0; 76 }