您的位置:首页 > 产品设计 > UI/UE

【UESTC】2015 UESTC Training for Data Structures

2015-12-17 00:30 316 查看
题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=102504#overview

这套题放了很久一直没写,直到我终于发现,现在已经不得不练数据结构的时候了,于是把这套题翻了出来开始写,嘛……总之感谢UESTC的题目先。估计全部写完大概要一周的时间,最近又因为期末考试没什么时间,大概会拖很久吧……

【UESTC1059】秋实大哥与小朋友

题意为对一个连续区间[1,n],有两种操作,将某一段区间的值增加v,或者查询某一个点的值。题目中给定的n很大,需要使用离散化,修改和查询使用线段树和树状数组完成均可,使用树状数组时,是“修改区间,查询点”的一种使用方式,具体操作为,在增加的时候,执行add(l,v)和add(r+1,-v),使[1,l-1]和[r+1,n]的值不变,只改变[l,r]区间的值。查询的时候执行query(x),统计x节点的值,类似于统计覆盖线段的一种做法。除此之外我还查到另一种解法……等我看懂了把代码贴上来。

#include<iostream>
#include<cstdio>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<queue>
#include<string>
#include<cstring>
#include<sstream>
#include<algorithm>
#include<cmath>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
using namespace std;
typedef long long LL;
struct Act{
int k,l,r;
LL v;
};
map<int,int> dir;
vector<int> sav;
Act a[100100];
LL t[300100];
int n,m,cnt;
int lowbit(int k) {
return k&(-k);
}
void add(int k,LL x) {
while (k <= cnt) {
t[k] += x;
k += lowbit(k);
}
}
LL query(int k) {
LL ans = 0;
while (k > 0) {
ans += t[k];
k -= lowbit(k);
}
return ans;
}
int main() {
while (scanf("%d%d",&n,&m) != EOF) {
dir.clear();
memset(t,0,sizeof(t));
sav.clear();sav.push_back(-1);
for (int i = 1;i <= m; i++) {
scanf("%d",&a[i].k);
if (!a[i].k) {
scanf("%d%d%lld",&a[i].l,&a[i].r,&a[i].v);
sav.push_back(a[i].l);sav.push_back(a[i].r);
} else {
scanf("%d",&a[i].l);
sav.push_back(a[i].l);
}
}
sort(sav.begin(),sav.end());cnt = 0;
for (int i = 1;i < sav.size();i++)
if (sav[i] != sav[i-1]) dir[sav[i]] = ++cnt;
for (int i = 1;i <= m; i++) {
if (!a[i].k) {
//cout << dir[a[i].l] << ":" << dir[a[i].r] << endl;
add(dir[a[i].l],a[i].v);
add(dir[a[i].r]+1,-a[i].v);
} else {
//cout << dir[a[i].v] << endl;
printf("%lld\n",query(dir[a[i].l]));
}
}
}
return 0;
}


【UESTC1057】秋实大哥与花

对于给定区间完成区间修改和区间查询,线段树的基本应用。

#include<iostream>
#include<cstdio>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<queue>
#include<string>
#include<cstring>
#include<sstream>
#include<algorithm>
#include<cmath>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
using namespace std;
typedef long long LL;
LL t[400100],lazy[400100];
void down(int l,int r,int k) {
int mid = (l + r) >> 1;
lazy[k<<1] += lazy[k];t[k<<1] += (mid-l+1)*lazy[k];
lazy[(k<<1)|1] += lazy[k];t[(k<<1)|1] += (r-mid)*lazy[k];
lazy[k] = 0;
}
void build(int l,int r,int k) {
if (l == r) {
lazy[k] = 0;
scanf("%lld",&t[k]);
return;
}
int mid = (l + r) >> 1;
build(l,mid,k<<1);
build(mid+1,r,(k<<1)|1);
t[k] = t[k<<1] + t[(k<<1)|1];
}
void updata(int l,int r,int k,int x,int y,LL val) {
//printf("%d %d %d\n",l,r,k);
if (x <= l && r <= y) {
lazy[k] += val;
t[k] += (r-l+1)*val;
return;
}
if (lazy[k]) down(l,r,k);
int mid = (l+r) >> 1;
if (x <= mid) updata(l,mid,k<<1,x,y,val);
if (y > mid) updata(mid+1,r,(k<<1)|1,x,y,val);
t[k] = t[k<<1] + t[(k<<1)|1];
}
LL query(int l,int r,int k,int x,int y) {
//printf("%d %d %d\n",l,r,t[k]);
if (x <= l && r <= y) {
return t[k];
}
if (lazy[k]) down(l,r,k);
int mid = (l + r) >> 1;LL s1 = 0,s2 = 0;
if (x <= mid) s1 = query(l,mid,k<<1,x,y);
if (y > mid) s2 = query(mid+1,r,(k<<1)|1,x,y);
return s1+s2;
}
int main() {
int n,m;
int l,r;LL v;
while (scanf("%d",&n) != EOF) {
build(1,n,1);
scanf("%d",&m);
for (int i = 1;i <= m; i++) {
scanf("%d%d%lld",&l,&r,&v);
updata(1,n,1,l,r,v);
printf("%lld\n",query(1,n,1,l,r));
}
}
return 0;
}


【UESTC1060】秋实大哥与快餐店

给出一些数a[1..n],有两种操作,再给出一个数a[i],或是对一个数k,求出给定的数中与k异或值最大的数。字典树的应用,可以将给出的数a[i]转换为二进制串后,从高位到低位进行建树(为保证位数相同需要补零)。对于给定的数k,在走到第i层节点时,尽量寻找与k第i位值不同的节点,这样找到的数就是与k异或值最大的数。

#include<iostream>
#include<cstdio>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<queue>
#include<string>
#include<cstring>
#include<sstream>
#include<algorithm>
#include<cmath>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
using namespace std;
struct node{
int k,next[2];
};
vector<node> a;
int cnt,root;
int newnode() {
node n;
n.k = n.next[0] = n.next[1] = 0;
a.push_back(n);
//cout << cnt << endl;
return a.size()-1;
}
void ins(int x) {
int p = root,k;
for (int i = 21;i >= 0; i--) {
k = x&(1 << i)?1:0;

//cout << k << endl;
if (!a[p].next[k]) {
int sav = newnode();

4000
a[p].next[k] = sav;
//cout << a[p].next[k] << endl;
}
//printf("%d %d %d\n",p,a[p].next[0],a[p].next[1]);
p = a[p].next[k];
}
}
int query(int x) {
int p = root,k,ans = 0;
for (int i = 21;i >= 0; i--) {
k = x&(1 << i)?0:1;
if (!a[p].next[k]) k = 1 - k;
if (k) ans += (1 << i);
p = a[p].next[k];
}
return ans;
}
int main() {
int n,m,x,y;
while (scanf("%d",&n) != EOF) {
a.clear();cnt = 0;
root = newnode();
for (int i = 1;i <= n; i++) {
scanf("%d",&x);
ins(x);
}
scanf("%d",&m);
while (m--) {
scanf("%d%d",&x,&y);
if (!x) ins(y);
else printf("%d\n",query(y));
}
}
return 0;
}


【UESTC1061】秋实大哥与战争

问题的实质在于寻找士兵k左右最近的死亡士兵,设左边最近的死亡士兵为l,右边的为r,则答案为r-l-1,也就是说,我们要完成(1)添加一个数(2)删除一个数(3)寻找与给定的数k最近的两个数,而集合set恰好能满足我们的需要(set是有序的,可以使用lower_bound进行查询),我们使用两个集合,一个集合存储正的坐标用来寻找l,另一个存储负坐标用于寻找r,在最开始需要把n+1和0添加到集合中。

#include<iostream>
#include<cstdio>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<queue>
#include<string>
#include<cstring>
#include<sstream>
#include<algorithm>
#include<cmath>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
using namespace std;
set<int> Sinc,Sdec;
int main() {
int n,m;
int act,k;
while (scanf("%d%d",&n,&m) != EOF) {
Sinc.clear();Sdec.clear();
Sinc.insert(n+1);
Sdec.insert(0);
while (m--) {
scanf("%d%d",&act,&k);
if (act == 0) {Sinc.insert(k);Sdec.insert(-k);}
if (act == 1) {Sinc.erase(k);Sdec.erase(-k);}
if (act == 2) {
set<int>::iterator st = Sinc.lower_bound(k);
set<int>::iterator ed = Sdec.lower_bound(-k);
if (*st == k) puts("0");
else printf("%d\n",(*st)+(*ed)-1);
}
}
}
return 0;
}


【UESTC1063】秋实大哥与妹纸

寻找a1...an的中位数,即第k大数问题,用堆或快排的折半查找均可。

#include<iostream>
#include<cstdio>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<queue>
#include<string>
#include<cstring>
#include<sstream>
#include<algorithm>
#include<cmath>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
using namespace std;
typedef unsigned int LL;
LL a[250000],m;
void add(int k) {
LL val = a[k];
while (k > 1) {
if (val > a[k >> 1]) {
a[k] = a[k >> 1];
k >>= 1;
} else break;
}
a[k] = val;
}
void del() {
LL val = a[m--],k = 1;
while (k < m) {
if ((k << 1) > m) break;
if ((k << 1) == m || a[(k << 1)|1] < a[k << 1]) {
if (a[(k << 1)] > val) {
a[k] = a[(k << 1)];
k = (k << 1);
} else break;
} else {
if (a[(k << 1)|1] > val) {
a[k] = a[(k << 1)|1];
k = (k << 1)|1;
} else break;
}
}
a[k] = val;
}
int main() {
int n,k,mid;
scanf("%d",&n);mid = n/2 + 1;
for (int i = 1;i <= mid; i++) {
scanf("%ud",&a[++m]);
add(m);
}
for (int i = mid+1;i <= n; i++) {
scanf("%ud",&a[++m]);
add(mid+1);
del();
}
//for (int i = 1;i <= mid; i++) cout << a[i] << " ";cout << endl;
if ((n&1) == 0) {
int k = a[1];del();
printf("%.1lf\n",(k+a[1])/2.0);
} else {
printf("%.1lf\n",(double)a[1]);
}
return 0;
}


【UESTC1069】秋实大哥去打工

寻找最大的连续矩形,明显的,最大矩形的高度一定与某个给定的矩形高度相等,所以对于每一个给定的矩形,以ai为高度的连续矩形可以向左右延伸,直到找到aj<ai为止。使用单调栈存储递增的矩形序列,入栈时确定了连续矩形的左边界,出栈时确定了连续矩形的右边界。

#include<iostream>
#include<cstdio>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<queue>
#include<string>
#include<cstring>
#include<sstream>
#include<algorithm>
#include<cmath>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
using namespace std;
struct mat{
int h,w;
};
mat Q[200100];
int main() {
int n;
scanf("%d",&n);
mat m;
int p = 0,ans = 0;
for (int i = 1;i <= n; i++) {
scanf("%d%d",&m.w,&m.h);
int sumw = 0;
while (p > 0 && m.h <= Q[p].h) {
ans = max(ans,Q[p].h*(Q[p].w+sumw));
sumw += Q[p--].w;
}
m.w += sumw;
Q[++p] = m;
}
int sumw = 0;
while (p > 0) {
ans = max(ans,Q[p].h*(Q[p].w + sumw));
sumw += Q[p--].w;
}
printf("%d\n",ans);
return 0;
}


【UESTC1070】秋实大哥打游戏

有权并查集,添加一个dis[i]数组表示i节点到f[i]节点的距离,在find中更新f[i]和dis[i]数组,注意读入有坑……最后一行没换行。

#include<iostream>
#include<cstdio>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<queue>
#include<string>
#include<cstring>
#include<sstream>
#include<algorithm>
#include<cmath>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
using namespace std;
const int maxn = 1e5 + 100;
int f[maxn],dis[maxn];
stack<int> S;
int find(int k) {
while (f[k] != k) {
S.push(k);
k = f[k];
}
int sum = 0;
while (!S.empty()) {
int p = S.top();S.pop();
sum += dis[p];dis[p] = sum;
f[p] = k;
}
return k;
}
int main() {
int n,x,y,fy;char ch;
scanf("%d",&n);
for (int i = 1;i <= n; i++) {f[i] = i;dis[i] = 0;}
while (scanf(" %c",&ch) != EOF && ch != 'O') {
if (ch == 'E') {
scanf("%d",&x);
find(x);
printf("%d\n",dis[x]);
}
if (ch == 'I') {
scanf("%d%d",&x,&y);
x = find(x);fy = find(y);
if (x != fy) {f[x] = y;dis[x] = abs(x-y)%1000;}
}
}
//for (int i = 1;i <= n; i++) printf("%d %d\n",f[i],dis[i]);
return 0;
}


【UESTC1073】秋实大哥与线段树

没什么可说的……

#include<iostream>
#include<cstdio>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<queue>
#include<string>
#include<cstring>
#include<sstream>
#include<algorithm>
#include<cmath>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 100;
int n,m;
LL a[maxn],t[maxn];
void add(int k,int val) {
for (int i = k;i <= n; i += i&(-i)) t[i] += val;
}
LL query(int k) {
LL ans = 0;
for (int i = k;i > 0; i -= i&(-i)) ans += t[i];
return ans;
}
int main() {
int l,r,k;
scanf("%d",&n);
for (int i = 1;i <= n; i++) {
scanf("%d",&a[i]);
add(i,a[i]);
}
scanf("%d",&m);
for (int i = 1;i <= m; i++) {
scanf("%d%d%d",&k,&l,&r);
if (k == 1) {add(l,r-a[l]);a[l] = r;}
if (k == 2) printf("%lld\n",query(r)-query(l-1));
}
return 0;
}


【UESTC1074】秋实大哥搞算数

四则表达式计算,栈的基本应用,正统做法是为运算符规定优先级……这里因为没有括号就偷懒了。减法运算转化为加上负数可以使运算简便一些。

#include<iostream>
#include<cstdio>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<queue>
#include<string>
#include<cstring>
#include<sstream>
#include<algorithm>
#include<cmath>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
using namespace std;
typedef long long LL;
string st;
stack<LL> num;
stack<char> op;
void fig() {
LL k2 = num.top();num.pop();
LL k1 = num.top();num.pop();
char act = op.top();op.pop();
//cout << k1 << act << k2 << endl;
if (act == '+') k1 += k2;
if (act == '-') k1 -= k2;
if (act == '*') k1 *= k2;
if (act == '/') k1 /= k2;
num.push(k1);
}
int main() {
int t;
scanf("%d",&t);
while (t--) {
num.push(0);
LL k = 0;int sgn = 1;
cin >> st;
for (int i = 0;i < st.size(); i++) {
if (st[i] >= '0' && st[i] <= '9') k = k*10 + (st[i] - '0')*sgn;
else {
//cout << k << endl;
num.push(k);k = 0;
while (!op.empty() && (op.top() == '*' || op.top() == '/')) fig();
if (st[i] == '-') {
st[i] = '+';
sgn = -1;
} else sgn = 1;
op.push(st[i]);
}
}
num.push(k);k = 0;
while (!op.empty()) fig();
if (!num.empty()) {
printf("%lld\n",num.top());
while (!num.empty()) num.pop();
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  acm uestc 数据结构