@01010101
2018-10-17T13:42:23.000000Z
字数 5246
阅读 1037
T1
这是个二维平面世界,平面上有n个特殊的果实,我从(0,0)点出发,希望得到尽量多的果实,但是出于某种特殊的原因,我的运动方式只有三种(假设当前我在(x,y)):
1、我可以走到(x+1,y)
2、我可以走到(x,y+1)
3、我可以走到(x+1,y+1)
现在我需要你的帮助,帮我找出我最多能够得到多少个果实。
1<=n<=100000,-10^9<=x,y<=10^9
用带一点点扫描线的思想来想,如果按横坐标排序,那么数量就是纵坐标不断递增的。就是最长上升子序列了。
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;int read(){char ch;int op=1;while((ch=getchar())<'0'||ch>'9') if(ch=='-') op=-1;int ret=ch-'0';while((ch=getchar())>='0'&&ch<='9') ret=ret*10+ch-'0';return ret*op;}const int N=100000+10;int n,cnt;int t[N];struct node{int xx,yy;bool operator < (const node &b) const{if(xx!=b.xx) return xx<b.xx;return yy<b.yy;}}a[N];int main(){freopen("find.in","r",stdin);freopen("find.out","w",stdout);n=read();for(int i=1;i<=n;++i){a[i].xx=read();a[i].yy=read();}sort(a+1,a+n+1);for(int i=1;i<=n;++i){if(a[i].xx<0||a[i].yy<0) continue;int b=a[i].yy;if(b>=t[cnt]){t[++cnt]=b;}else{int l=1,r=cnt,mid,ans=-1;while(l<=r){int mid=(l+r)>>1;if(t[mid]>b) {ans=mid;r=mid-1;}else l=mid+1;}if(ans!=-1) t[ans]=b;}}printf("%d\n",cnt);return 0;}
T2
这是个奇异的世界,世界上的n-1条路联结起来形成一棵树,每条路有一个对应的权值ci。
现在我会给出q组询问或操作。
每次询问我会从一个x点走到y点,初始在x点我会有一个数字v,然后每走过一条权值为c的边,我的v就会变成,问最后到y时v变成了什么。
每次修改我会修改一条边的权值,保证修改后的权值小于等于原来的权值且不会小于1。
每组询问或操作的格式如下:
询问:1 x y v表示从x走到y,一开始的数字为v。
操作:2 p c表示将第p条边的边权修改为c
n,q<=100000,c_i,v_i <= 10^{18}
显然,走过一条非1边后边权至少减半。所以有两种维护方式:1边,或0边。
对于1边:可以用并查集进行路径压缩。
对于0边:可以用树链剖分维护从当前点到根的路径乘积,用double进行乘,超过1e18就置为0。
此题不需要维护精度:
有两个结论:
1.
向下取整只与数值有关,与数的先后无关。
2.
向下取整可以变连除为除一个。
#include <iostream>#include <cstdio>#include <cstring>#define ll long longusing namespace std;ll read(){char ch;ll op=1;while((ch=getchar())<'0'||ch>'9') if(ch=='-') op=-1;ll ret=ch-'0';while((ch=getchar())>='0'&&ch<='9') ret=ret*10+ch-'0';return ret*op;}void write(ll x){if(x<0) putchar('-'),x=-x;if(x>=10) write(x/10);putchar('0'+x%10);}const ll N=100000+10;const ll D=20;ll n,m,k,q;ll head[N],cst[N],f[N],d[N],fa[N][D+2];struct edge{ll v,w,nxt;}e[N<<1];void adde(ll u,ll v,ll w){e[k].v=v;e[k].w=w;e[k].nxt=head[u];head[u]=k++;}ll Find(ll x){return (f[x]==x)?x:f[x]=Find(f[x]);}void dfs(ll u,ll fath){d[u]=d[fath]+1;fa[u][0]=fath;for(ll i=head[u];i!=-1;i=e[i].nxt){ll v=e[i].v;if(v!=fath){if(e[i].w==1) f[v]=Find(u);else f[v]=v;dfs(v,u);cst[v]=e[i].w;}}}ll Lca(ll u,ll v){if(d[u]<d[v]) swap(u,v);for(ll i=D;i>=0;--i){if(d[fa[u][i]]>=d[v]) u=fa[u][i];}if(u==v) return u;for(ll i=D;i>=0;--i){if(fa[u][i]!=fa[v][i]){u=fa[u][i];v=fa[v][i];}}return fa[u][0];}ll up_tree(ll u,ll t,ll cc){while(d[u]>d[t]&&cc!=0){cc/=cst[u];if(f[u]!=u) u=f[u];else u=fa[u][0];}return cc;}ll a,b,c,op;int main(){// freopen("walk.in","r",stdin);// freopen("walk.out","w",stdout);memset(head,-1,sizeof(head));scanf("%lld%lld",&n,&q);for(ll i=1;i<n;++i){a=read();b=read();c=read();adde(a,b,c);adde(b,a,c);}f[1]=1;dfs(1,0);for(ll i=1;i<=D;++i){for(ll j=1;j<=n;++j){fa[j][i]=fa[fa[j][i-1]][i-1];}}while(q--){op=read();if(op==1){a=read();b=read();c=read();ll l=Lca(a,b);write(up_tree(b,l,up_tree(a,l,c)));putchar('\n');}else{a=read();b=read();if(b==1) {f[e[2*a-2].v]=Find(e[2*a-1].v);}cst[e[2*a-2].v]=b;}}return 0;}
T3
这是个有n个点的世界,有m条无向边连接着这n个点,但是不保证点之间能够互相到达。
“这个世界的夕阳,只在奇数长的简单路径的尽头。”一个神如是说。
于是我想知道对于一个点对(x,y),x到y之间的所有简单路径中是否存在长度为奇数的路径,只有这样,我才能找到存在有夕阳的路。保证没有自环与重边。
1≤n,q,m≤100000
此题的考察知识较多。
题解:
假设我们现在对原图先得到一棵生成树(其实应该是森林,毕竟不保证联通)
那么我们对于询问(x,y),我们要看的其实是在生成树上x到y的路径上是否存在在某个奇环内的边(“奇环”指长度为奇数的环)。
于是问题转化成看一条边是否在奇环中,一个很直观的想法是,对于一个强连通分量,如果在这个强连通分量中存在一条在奇环中的边,那么所有在强连通分量里的边都是存在于某一个奇环中的。
那么如何在一个强连通分量里找到是否有在奇环中的边呢?我们对这个图做tarjan,对于一条虚边(u,v)如果dep[u]与dep[v]的奇偶性相同(dep[u]表示u在树中的深度),那么u到v的路径上的边都是在奇环中的。
于是我们可以得到每条边是否存在于奇环中,问题就变得很简单了。
对于一个询问(x,y)如果dep[x]和dep[y]奇偶性不同,那么是yes的
否则如果在x到y的路径上存在有在奇环中的边,那么也是yes的,这个可以通过预处理出点到根节点的路径上的这种边的个数得到。
再否则就只有no了。
注意:弹栈要在退栈的时候弹。
const int N=100000+10;const int D=20;int n,m,k,tp,idx;int head[N],d[N],fa[N][D+2],dfn[N],low[N],sta[N],odd[N],s[N],vis[N];struct edge{int v,nxt;}e[N<<1];void adde(int u,int v){e[k].v=v;e[k].nxt=head[u];head[u]=k++;}void tarjan(int u,int fath){d[u]=d[fath]+1;fa[u][0]=fath;dfn[u]=low[u]=++idx;sta[++tp]=u;for(int i=head[u];i!=-1;i=e[i].nxt){int v=e[i].v;if(!dfn[v]){tarjan(v,u);low[u]=min(low[u],low[v]);}else if(v!=fath){if((d[u]&1)==(d[v]&1)) odd[u]=1;low[u]=min(low[u],dfn[v]);}}if(dfn[u]==low[u]){int pos=tp,w=0;while(sta[pos]!=u) w|=(odd[sta[pos--]]);if(w==1) {while(sta[tp]!=u) s[sta[tp--]]++;}else tp=pos-1;//!!不能再忘else了!!!!}}int Lca(int u,int v){if(d[u]<d[v]) swap(u,v);for(int i=D;i>=0;--i){if(d[fa[u][i]]>=d[v]) u=fa[u][i];}if(u==v) return u;for(int i=D;i>=0;--i){if(fa[u][i]!=fa[v][i]){u=fa[u][i];v=fa[v][i];}}if(fa[u][0]==fa[v][0]) return fa[u][0];return -1;}void dfs(int u,int fath){for(int i=head[u];i!=-1;i=e[i].nxt){int v=e[i].v;if(fa[v][0]==u){vis[v]=1;s[v]+=s[u];dfs(v,u);}}}int a,b,q;int main(){// freopen("a.txt","r",stdin);memset(head,-1,sizeof(head));n=read();m=read();for(int i=1;i<=m;++i){a=read();b=read();adde(a,b);adde(b,a);}for(int i=1;i<=n;++i){if(!dfn[i]){tarjan(i,i);}}for(int i=1;i<=D;++i){for(int j=1;j<=n;++j){fa[j][i]=fa[fa[j][i-1]][i-1];}}for(int i=1;i<=n;++i){if(fa[i][0]==i){dfs(i,i);}}q=read();while(q--){a=read();b=read();int l=Lca(a,b);if(l==-1) {puts("No");continue;}if(((d[a]+d[b]-2*d[l])&1)==1) {puts("Yes");continue;}if(s[a]+s[b]>2*s[l]) {puts("Yes");continue;}puts("No");}}